Skip to content

fix(persistence): enable WAL, busy_timeout, and FK on SQLite#101

Merged
RaghavChamadiya merged 1 commit intomainfrom
fix/sqlite-wal-busy-timeout
Apr 26, 2026
Merged

fix(persistence): enable WAL, busy_timeout, and FK on SQLite#101
RaghavChamadiya merged 1 commit intomainfrom
fix/sqlite-wal-busy-timeout

Conversation

@RaghavChamadiya
Copy link
Copy Markdown
Collaborator

Closes #95.

Summary

Two concurrent `repowise update` invocations on the same workspace would trip `sqlite3.OperationalError: database is locked`. The default SQLite `journal_mode` is `delete`, which serialises writers and immediately fails any second writer instead of giving it a retry window.

What changed

Register a `connect` event listener on SQLite-backed engines that runs on every new physical connection and sets:

PRAGMA Value Why
`journal_mode` `WAL` Readers can proceed while a writer is active
`synchronous` `NORMAL` The safe pairing for WAL
`busy_timeout` `5000` 5 seconds of polite back-off before giving up
`foreign_keys` `ON` Matches PostgreSQL behaviour, makes FK cascades work in tests too

WAL is a file-level setting that persists across opens, but the listener re-applies it defensively in case the database file was created by an older repowise version, by alembic, or by a third-party tool that left `journal_mode` at the default.

PostgreSQL engines are unchanged.

Tests

Four unit tests in `tests/unit/persistence/test_database_pragmas.py`:

  • WAL is set on file-backed engines.
  • `busy_timeout` is at least 1 second.
  • Foreign keys are enforced.
  • Two concurrent writers against the same database file both succeed (this is the regression test for the original report).
  • A separate sync-driver smoke test confirms WAL persists in the file.

Two concurrent 'repowise update' invocations on the same workspace would
trip 'sqlite3.OperationalError: database is locked' (#95). The default
SQLite journal_mode is delete, which serialises writers and immediately
fails any second writer instead of giving it a retry window.

Register a 'connect' event listener on the SQLite-backed engines that
runs on every new physical connection and sets:

  PRAGMA journal_mode = WAL          (lets readers proceed during a write)
  PRAGMA synchronous = NORMAL        (the safe pairing for WAL)
  PRAGMA busy_timeout = 5000         (5 seconds of polite back-off)
  PRAGMA foreign_keys = ON           (matches PostgreSQL behaviour)

WAL is a file-level setting that persists across opens, but the listener
re-applies it defensively in case the database file was created by an
older repowise version, alembic, or a third-party tool that left
journal_mode at default. PostgreSQL engines are unchanged.

Adds four unit tests covering each pragma plus a concurrent-writers
test that fails on main with OperationalError.
@RaghavChamadiya RaghavChamadiya merged commit ec2cfae into main Apr 26, 2026
5 checks passed
@RaghavChamadiya RaghavChamadiya deleted the fix/sqlite-wal-busy-timeout branch April 26, 2026 10:59
@RaghavChamadiya RaghavChamadiya mentioned this pull request Apr 26, 2026
RaghavChamadiya added a commit that referenced this pull request Apr 26, 2026
* feat: improve PreToolUse hook relevance with multi-signal search

Replace FTS-only file retrieval with a 3-signal ranking system:
- Symbol name match (weight 2.0) — most precise
- File path match (weight 1.5) — catches path-based searches
- FTS on wiki content (weight 1.0) — broadest, lowest priority
Files ranked by signal score then PageRank, top 3 returned.

Remove git signals (HOTSPOT, bus-factor, owner) from enrichment —
that info belongs in get_risk, not every search. Remove Bash command
interception (fragile regex on grep/rg commands).

Keep: symbols (3), importers (3), dependencies (2) per file.

* release: v0.3.1

Bumps repowise to 0.3.1 across pyproject.toml and the three sub-package
__init__.py files.

Highlights since 0.3.0:

- Output language support for generated wiki content (#99)
- Luau / Roblox language support (#89)
- OpenRouter LLM and embedding provider (#56)
- base_url plus per-provider env vars for OpenAI / Anthropic / Gemini /
  Ollama / LiteLLM (#85)
- SQLite WAL plus busy_timeout plus FK constraints, fixing concurrent
  'repowise update' database is locked errors (#101)
- CLAUDE.md opt-out prompt now asked in both full and advanced modes
  and the answer is honoured (#102)
- repowise init no longer silently overwrites unparseable user JSON
  configs (#94)
- pyproject packages list resynced with the language-support refactor
  so editable installs and CI build cleanly (#97)
- uv workflow documented and dev deps migrated to PEP 735
  dependency-groups, silencing the tool.uv.dev-dependencies deprecation
  warning (#100)
- Five Dependabot security bumps (dompurify, gitpython, mako, litellm,
  python-multipart)

Also flips the project URLs and serve_cmd's _GITHUB_REPO constant from
RaghavChamadiya/repowise to repowise-dev/repowise so 'repowise serve'
can locate the published web UI tarball.
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.

OperationalError: database is locked on concurrent repowise update

2 participants