Skip to content

docs: explain SQLite concurrency caveats + DSN tuning (RUK-137) - #22

Merged
ruko1202 merged 1 commit into
mainfrom
feature/ruk-137
May 25, 2026
Merged

docs: explain SQLite concurrency caveats + DSN tuning (RUK-137)#22
ruko1202 merged 1 commit into
mainfrom
feature/ruk-137

Conversation

@ruko1202

Copy link
Copy Markdown
Owner

The original ticket asked for runtime WAL verification, but auditing
the code showed nothing actually depends on WAL being on — the
"In WAL mode the transaction provides row-level locking" comment in
sqlite/get_for_processing.go is a vestigial note, not a real
dependency. Adding code to enable+check WAL would have been
ceremonial.

What is real and worth telling users:

  • SQLite serializes writes at the file level. Multiple goque workers
    calling CureTasks / GetTasksForProcessing in parallel hit
    SQLITE_BUSY immediately because dbtx.WithinTx uses BEGIN DEFERRED:
    the SELECT takes a SHARED lock, the UPDATE can't upgrade to
    RESERVED, and _busy_timeout does NOT apply to lock upgrades. The
    fix is to start tx as BEGIN IMMEDIATE via the _txlock=immediate
    DSN parameter — surfaced in README as a copy-pasteable snippet.

  • Single-binary constraint: even with the DSN tuning, two processes
    pointing at the same .sqlite.db file will deadlock.

If you need real concurrency, the message stays the same: PG or
MySQL.

Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com

The original ticket asked for runtime WAL verification, but auditing
the code showed nothing actually depends on WAL being on — the
"In WAL mode the transaction provides row-level locking" comment in
sqlite/get_for_processing.go is a vestigial note, not a real
dependency. Adding code to enable+check WAL would have been
ceremonial.

What is real and worth telling users:

- SQLite serializes writes at the file level. Multiple goque workers
  calling CureTasks / GetTasksForProcessing in parallel hit
  SQLITE_BUSY immediately because dbtx.WithinTx uses BEGIN DEFERRED:
  the SELECT takes a SHARED lock, the UPDATE can't upgrade to
  RESERVED, and _busy_timeout does NOT apply to lock upgrades. The
  fix is to start tx as BEGIN IMMEDIATE via the _txlock=immediate
  DSN parameter — surfaced in README as a copy-pasteable snippet.

- Single-binary constraint: even with the DSN tuning, two processes
  pointing at the same .sqlite.db file will deadlock.

If you need real concurrency, the message stays the same: PG or
MySQL.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@ruko1202
ruko1202 merged commit 851ea42 into main May 25, 2026
4 checks passed
@ruko1202
ruko1202 deleted the feature/ruk-137 branch May 25, 2026 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant