From 4810898cfa931eb475af2ced48532767bc1c5a7e Mon Sep 17 00:00:00 2001 From: rayhpeng Date: Sat, 11 Apr 2026 11:25:14 +0800 Subject: [PATCH] chore(persistence): drop redundant busy_timeout PRAGMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Python's sqlite3 driver defaults to a 5-second busy timeout via the ``timeout`` kwarg of ``sqlite3.connect``, and aiosqlite + SQLAlchemy's aiosqlite dialect inherit that default. Setting ``PRAGMA busy_timeout=5000`` explicitly was a no-op — verified by reading back the PRAGMA on a fresh connection (it already reports 5000ms without our PRAGMA). Concurrent stress test (50 checkpoint writes + 20 event batches + 50 thread_meta updates on the same deerflow.db) still completes with zero errors and 200/200 rows after removing the explicit PRAGMA. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../packages/harness/deerflow/config/database_config.py | 7 +++---- backend/packages/harness/deerflow/persistence/engine.py | 6 +++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/backend/packages/harness/deerflow/config/database_config.py b/backend/packages/harness/deerflow/config/database_config.py index 19fb297b0..37cfd579d 100644 --- a/backend/packages/harness/deerflow/config/database_config.py +++ b/backend/packages/harness/deerflow/config/database_config.py @@ -7,10 +7,9 @@ configures one backend; the system handles physical separation details. SQLite mode: checkpointer and app share a single .db file ({sqlite_dir}/deerflow.db) with WAL journal mode enabled on every connection. WAL allows concurrent readers and a single writer without -blocking, making a unified file safe for both workloads. The -``busy_timeout`` PRAGMA (set in ``engine.py``) ensures writers wait -for each other instead of failing immediately when they contend for -the write lock. +blocking, making a unified file safe for both workloads. Writers +that contend for the lock wait via the default 5-second sqlite3 +busy timeout rather than failing immediately. Postgres mode: both use the same database URL but maintain independent connection pools with different lifecycles. diff --git a/backend/packages/harness/deerflow/persistence/engine.py b/backend/packages/harness/deerflow/persistence/engine.py index 4857c13a0..2777c2450 100644 --- a/backend/packages/harness/deerflow/persistence/engine.py +++ b/backend/packages/harness/deerflow/persistence/engine.py @@ -98,6 +98,11 @@ async def init_engine( # SQLite deployment (TC-UPG-06 in AUTH_TEST_PLAN.md). The companion # ``synchronous=NORMAL`` is the safe-and-fast pairing — fsync only # at WAL checkpoint boundaries instead of every commit. + # Note: we do not set PRAGMA busy_timeout here — Python's sqlite3 + # driver already defaults to a 5-second busy timeout (see the + # ``timeout`` kwarg of ``sqlite3.connect``), and aiosqlite / + # SQLAlchemy's aiosqlite dialect inherit that default. Setting + # it again would be a no-op. @event.listens_for(_engine.sync_engine, "connect") def _enable_sqlite_wal(dbapi_conn, _record): # noqa: ARG001 — SQLAlchemy contract cursor = dbapi_conn.cursor() @@ -105,7 +110,6 @@ async def init_engine( cursor.execute("PRAGMA journal_mode=WAL;") cursor.execute("PRAGMA synchronous=NORMAL;") cursor.execute("PRAGMA foreign_keys=ON;") - cursor.execute("PRAGMA busy_timeout=5000;") finally: cursor.close() elif backend == "postgres":