Worker: an idle worker writes two log lines and a heartbeat file every two seconds, and its log pushes real errors out of the kept log in about a day #1117
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#1117
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/core/management/commands/work.py:60-86builds a new upstreamWorkerin batch mode on every pass, runs it, writes the worker heartbeat (scheduler.worker_beat,core/scheduler.py:111, amkstempplusos.replaceon the shared volume) and sleeps--every(default 2 s, line 39).The installed
django_tasks_db0.13.0 (.venv/Lib/site-packages/django_tasks_db/management/commands/db_worker.py) logs at INFO on loggerdjango_tasks_db: "Starting worker worker_id=… queues=…" at the top ofrun()(line 96) and "No more tasks to run for worker_id=… - exiting gracefully." when a batch finds the queue empty (line 139). So an idle worker emits two INFO lines per pass, one pass every 2 s plus the pass time: about 43,200 passes and 86,400 lines a day.Upstream's own
db_workercommand sets that logger's level inconfigure_logging(line 307);workconstructsWorkerdirectly and never calls it, so the logger inherits the root level.LOGGINGinsrc/postulo/config/settings/base.py:1004-1015quietensfontTools,weasyprint,httpxandhttpcore, notdjango_tasks_db; root is INFO with both the console and the shared JSON file handler (lines 1017-1019).Measured:
postulo.core.logs.JSONFormatterrenders the two lines at 159 and 175 bytes (one call each under the test settings). That is about 337 bytes a pass, about 14.5 MB a day intodata/logs/postulo.log. The file rotates atPOSTULO_LOG_MAX_BYTES5 MB with 3 backups (lines 945-946), 20 MB in all, and every process (web, scheduler, worker) shares it. An idle worker alone therefore rotates the kept log, including the web's errors shown on the staff log page, in about 1.4 days. The same lines go todocker logsfor the worker container, unbounded (see D6).Each pass also opens a fresh database connection (
close_old_connections()with the defaultCONN_MAX_AGE0, which closes after every loop, so each pass reconnects and reruns theinit_commandPRAGMAs ofconfig/sqlite.py:53) and takes anEXCLUSIVEtransaction on SQLite for the claim (django_tasks_db/utils.pyexclusive_transaction). Both are short; they are part of the cost of the 2 s poll, not a separate finding.Rebuilding the
Workerobject per pass costs nothing worth naming; the scout's "rebuilds upstreamWorkerevery 2 s" is true but not where the cost is.The worker healthcheck accepts a heartbeat up to 5 minutes old (
docker/compose.yml:111,docker/compose.postgres.yml:112), and the staff overview shows its age (core/server_views.py:260).What would change
"django_tasks_db": {"level": "WARNING"}toLOGGING["loggers"]besidehttpx. Shutdown warnings (lines 66, 72) and "Task id=… failed unexpectedly" (logger.exception, line 197) still appear. Optionally log one INFO line of Postulo's own when theworkcommand starts, sodocker logsstill shows that the worker came up.work.py, write the heartbeat only when the last one is more than 60 s old (keep a monotonic timestamp in the loop). The 5-minute healthcheck and the overview's "last pass" stay correct to within a minute.No library needed; this is configuration and a few lines in the command.
What it saves or protects
large: about 86,400 log lines (about 14.5 MB of JSON) a day from an idle worker gone, so the 20 MB kept log holds weeks instead of about 1.4 days; 43,200 heartbeat file writes a day cut to about 1,440
Accessibility
none
Decided by the maintainer (2026-10-31)
quieten django_tasks_db to WARNING and write the heartbeat at most once a minute
Decisions
django_tasks_dbto WARNING? Recommended: yes. The two lines say nothing an operator acts on; failures and stops are still logged.Found by the efficiency and reliability audit of 2026-10-30 (finding B1; index postulo/postulo#1108). Checked against
mainatdaee30b15(2026-10-30).