diora-web/docs/database.md
mrwnslz b09a4625a4
Some checks failed
Build and push Docker image / build (push) Successful in 16s
Test / e2e (push) Failing after 1m23s
Test / test (push) Successful in 9m15s
SQLite im WAL-Modus, Transaktionen IMMEDIATE: Leser warten nicht mehr auf lange Schreibvorgänge (Feed-Abruf, große Uploads) – kein „database is locked“ mehr bei GET /books/
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 15:04:37 +02:00

24 lines
1.4 KiB
Markdown

# The database
One SQLite file, `data/db.sqlite3` (on the server `/home/marwin/diora-prod-data`, mounted into
`diora-prod` at `/app/data`). The books live in it too, encrypted, so it is large (2.5 GB in
October 2026) and some writes are big (a scanned book of 30 MB).
## Write-ahead log (since 2026-10-19)
`diora/sqlite.py` puts every connection in WAL mode (`PRAGMA journal_mode=WAL`, set once per
file, it stays) with `synchronous=NORMAL`; `settings.DATABASES` has `transaction_mode:
IMMEDIATE`, so a transaction takes the write lock when it begins.
Why: in the rollback-journal mode before, a long write kept all readers out. The podcast
refresh (cron, every 15 minutes) and big uploads made requests fail with "database is
locked", GET /books/ among them — the apps then saw no new books and no changed titles.
With WAL, readers read on while one writer writes; writers still take turns (20 s timeout).
Next to `db.sqlite3` there are now `db.sqlite3-wal` and `db.sqlite3-shm`. They belong to the
database: a copy of `db.sqlite3` alone may miss the latest writes. To copy it safely:
docker exec diora-prod python -c "import sqlite3; s=sqlite3.connect('data/db.sqlite3'); d=sqlite3.connect('data/backup.sqlite3'); s.backup(d)"
or stop the container first. Back to the old mode, if ever needed:
`PRAGMA journal_mode=DELETE` (with no other connection open) and remove `diora/sqlite.py`'s hook.