SQLite: no journal size limit, no PRAGMA optimize and no way to compact the file #1128
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#1128
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What exists today
src/postulo/config/sqlite.py:51-55gives every file-backed SQLite connectiontransaction_mode: IMMEDIATE,PRAGMA journal_mode=WAL; PRAGMA synchronous=NORMAL;and a 20 s timeout. Nothing else: a grep ofsrc/postuloforVACUUM,wal_checkpoint,journal_size_limitandPRAGMA optimizefinds nothing, and the tracker has no issue on them.-walfile unlessjournal_size_limitis set; after a large write (an archive import, a restore, a big purge such as D1's first run) it stays at its high-water size until the last connection closes, which with three gunicorn workers, the scheduler and the worker rarely happens.PRAGMA optimizeperiodically on long-lived applications (or at connection open with0x10002since 3.46). Postulo never runs it, sosqlite_stat1is whatever a migration left, which for new indexes is nothing.VACUUMorauto_vacuumthe file never shrinks, and the backup copies it at full size.The image ships SQLite 3.50.4 through
python:3.14-slim-bookworm(docker/Dockerfile:137; the dev.venvreports 3.50.4 too), so every pragma below is available. PostgreSQL instances are unaffected.What would change
PRAGMA journal_size_limit=67108864;(64 MB) toFILE_OPTIONS["init_command"]inconfig/sqlite.py. Per connection, free.PRAGMA optimize;from the scheduler pass at most once a day, and from the hourly request-time tidy (core/slow.py:tidy_up_if_due) when there is no scheduler; it is a no-op when nothing changed. SQLite only, skipped on PostgreSQL (connection.vendor).manage.py compact_databasethat runsVACUUM(SQLite) after saying how much space it would give back (PRAGMA freelist_count×page_size), documented on the wiki's maintenance page. Not automatic:VACUUMtakes the write lock for its whole run and needs free disk equal to the database.No library; three SQL statements in the places that already own the database.
What it saves or protects
small: the
-walfile shrinks back after a burst instead of staying at its largest size, the query planner keeps current statistics, and an operator can give back the space that deletions (expired cache rows, task results, errands) leave inside the fileAccessibility
none
Decisions
Found by the efficiency and reliability audit of 2026-10-30 (finding D8; index postulo/postulo#1108). Checked against
mainatdaee30b15(2026-10-30).