Summary
After adding the first asset to a fresh install, the viewer stays on the standby screen indefinitely and logs Playlist is empty, even though the asset is enabled, active, and visible to both the server and viewer via the ORM. More broadly, the viewer's polling-based playlist refresh no longer detects asset edits at all under WAL.
Reproduced on a freshly-flashed x86 (Debian 13) install running master.
Root cause
The viewer detects DB changes by polling the main anthias.db file's mtime:
# src/anthias_viewer/scheduling.py
def get_db_mtime(self) -> float:
try:
return path.getmtime(settings['database'])
except (OSError, TypeError):
return 0
refresh_playlist() only calls update_playlist() when get_db_mtime() > last_update_db_mtime (or on a shuffle reshuffle, or when a deadline passes).
Since #3015 the database is opened with PRAGMA journal_mode=WAL. Under WAL, commits are written to the anthias.db-wal sidecar (and update anthias.db-shm); the main anthias.db file's mtime stays frozen until a checkpoint, which during normal operation is infrequent. So get_db_mtime() never advances and the poller never sees the change.
The two fallbacks don't save it:
- An empty starting playlist yields a
None deadline (_compute_deadline returns None when there are no candidates), so the deadline path never fires — this is why the first asset is the most visible failure.
- For a non-empty playlist the deadline is the soonest
end_date, which is typically far in the future, so edits still aren't picked up promptly.
This is a regression introduced by #3015 (WAL) — the viewer's change-detection was not updated to account for WAL's sidecar files.
Reproduction
- Fresh install, empty playlist.
POST /api/v2/assets with an enabled, currently-active asset.
- Viewer keeps logging
Playlist is empty; the asset never appears.
touch ~/.anthias/anthias.db (bump the main file's mtime) → viewer immediately logs Generating asset-list… Showing asset ….
Proposed fix
Make the change-detector WAL-aware: take the newest mtime across anthias.db, anthias.db-wal, and anthias.db-shm. Every commit updates the -wal/-shm mtime, and a checkpoint bumps the main file, so the max advances on every write regardless of journal mode. (Considered PRAGMA data_version as an alternative; the max-mtime approach keeps the existing cheap filesystem-stat design with no per-loop query.)
Related observations (not part of this fix)
- The v2 create endpoint (
AssetListViewV2.post) returns 201 without send_to_viewer('reload'), unlike update/delete — so there's no push-path backstop on create.
_handle_reload() reloads settings/rotation/skip-if-inactive only; it does not refresh the playlist (relies on the poller).
processing.py celery publishes raw 'reload' without the viewer topic prefix the subscriber splits on — suspected to be dropped; unverified.
Summary
After adding the first asset to a fresh install, the viewer stays on the standby screen indefinitely and logs
Playlist is empty, even though the asset is enabled, active, and visible to both the server and viewer via the ORM. More broadly, the viewer's polling-based playlist refresh no longer detects asset edits at all under WAL.Reproduced on a freshly-flashed x86 (Debian 13) install running
master.Root cause
The viewer detects DB changes by polling the main
anthias.dbfile's mtime:refresh_playlist()only callsupdate_playlist()whenget_db_mtime() > last_update_db_mtime(or on a shuffle reshuffle, or when a deadline passes).Since #3015 the database is opened with
PRAGMA journal_mode=WAL. Under WAL, commits are written to theanthias.db-walsidecar (and updateanthias.db-shm); the mainanthias.dbfile's mtime stays frozen until a checkpoint, which during normal operation is infrequent. Soget_db_mtime()never advances and the poller never sees the change.The two fallbacks don't save it:
Nonedeadline (_compute_deadlinereturnsNonewhen there are no candidates), so the deadline path never fires — this is why the first asset is the most visible failure.end_date, which is typically far in the future, so edits still aren't picked up promptly.This is a regression introduced by #3015 (WAL) — the viewer's change-detection was not updated to account for WAL's sidecar files.
Reproduction
POST /api/v2/assetswith an enabled, currently-active asset.Playlist is empty; the asset never appears.touch ~/.anthias/anthias.db(bump the main file's mtime) → viewer immediately logsGenerating asset-list… Showing asset ….Proposed fix
Make the change-detector WAL-aware: take the newest mtime across
anthias.db,anthias.db-wal, andanthias.db-shm. Every commit updates the-wal/-shmmtime, and a checkpoint bumps the main file, so the max advances on every write regardless of journal mode. (ConsideredPRAGMA data_versionas an alternative; the max-mtime approach keeps the existing cheap filesystem-stat design with no per-loop query.)Related observations (not part of this fix)
AssetListViewV2.post) returns 201 withoutsend_to_viewer('reload'), unlike update/delete — so there's no push-path backstop on create._handle_reload()reloads settings/rotation/skip-if-inactive only; it does not refresh the playlist (relies on the poller).processing.pycelery publishes raw'reload'without theviewertopic prefix the subscriber splits on — suspected to be dropped; unverified.