Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions backend/database/session.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Engine creation, initialization, and session management."""

import logging
import sqlite3 as _sqlite3
import uuid

from sqlalchemy import create_engine
Expand All @@ -21,6 +22,22 @@

logger = logging.getLogger(__name__)


def _make_connection(db_path: str) -> _sqlite3.Connection:
"""Open a SQLite connection with WAL journal mode and a 5-second busy timeout.

WAL allows concurrent readers while a write is in progress (the default
DELETE journal blocks all readers). This matters for voicebox because SSE
status polls and history queries run concurrently with the generation worker
writing to the same database. The busy timeout prevents "database is
locked" errors when two writers briefly contend on the same write slot.
"""
conn = _sqlite3.connect(db_path, check_same_thread=False)
conn.execute("PRAGMA journal_mode=WAL")
conn.execute("PRAGMA busy_timeout=5000")
return conn


# Initialized by init_db()
engine = None
SessionLocal = None
Expand All @@ -37,6 +54,14 @@ def init_db() -> None:
engine = create_engine(
f"sqlite:///{_db_path}",
connect_args={"check_same_thread": False},
# Each connection enables WAL journal mode and sets a 5-second busy
# timeout. WAL allows concurrent readers during a write (the default
# DELETE/ROLLBACK journal blocks all readers), which matters for
# voicebox because SSE status polls and history queries run
# concurrently with the generation worker writing to the same db.
# busy_timeout prevents "database is locked" errors when two
# connections briefly contend on the same write slot.
creator=lambda: _make_connection(str(_db_path)),
)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Expand Down