Web UI gets progressively slower over hours of uptime #132
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?
Cang's web interface gets progressively slower over hours to days of uptime. A daily container restart restores normal performance, pointing to a resource that accumulates and is reset on restart.
The primary cause is SQLite WAL file unbounded growth. WAL mode is enabled for concurrency, and the periodic camera scan writes new snapshot rows every few minutes. The default PASSIVE auto-checkpoint never succeeds because the web server always has at least one concurrent reader (e.g. the HTMX live-snapshot poll). The WAL accumulates write changes from every scan cycle indefinitely, and each read must scan the ever-growing WAL to find current page versions. Container restart triggers a RESTART checkpoint on close, truncating the WAL and restoring performance.
A secondary issue is that the calendar view (/days) runs a full table scan via SELECT DATE(recorded_at) AS day, COUNT(*), SUM(motion) FROM snapshots GROUP BY day ORDER BY day DESC — there is no index with recorded_at as the leftmost column.
With ~5000 snapshots/day from 2 cameras (soon doubling to 4 cameras), both the WAL accumulation and table scan degrade significantly over time.
Plan
1. Add WAL checkpoint after periodic scan cycle
In
src/cang/web/lifespan.py— afterawait _run_cleanup(cfg, db)returns in_periodic_scan, run:TRUNCATE mode blocks until all readers finish, then zeroes the WAL. This is safe because
_periodic_scanis the only writer path — no race with concurrent writes. The checkpoint runs once per scan cycle (every 5 min by default), so overhead is minimal.Also add
PRAGMA busy_timeout = 5000inopen_dbalongside the existing journal_mode/synchronous pragmas so readers don't wait indefinitely if a checkpoint briefly holds the lock.2. Add index on (recorded_at, motion)
In
src/cang/db.py— add a new migration V5 with:This turns the calendar GROUP BY into a single-pass index-only scan. It also speeds up
list_snapshots_for_daywithout a camera filter.Branch
fix/issue-132-wal-checkpoint-and-indexCommits
PR