Scheduling
The three schedules, how to set the digest slot, and what happens when a run is missed
The worker container runs everything on a schedule; the app container only runs what you
trigger by hand. How a digest is assembled is on
Digest and delivery.
The three schedules
| Job | What it does | Set where | Default |
|---|---|---|---|
| Ingest | Fetches every source and summarises new items | INGEST_CRON in .env | 0 */6 * * * (every 6 h) |
| Cleanup | Clears old article text (retention) | CLEANUP_CRON in .env | 15 4 * * * (daily 04:15) |
| Digest | Fetches once more, then writes and sends the digest | In the app, under Settings | Weekly, Sunday 17:00 |
All three are evaluated in DIGEST_TIMEZONE (default UTC). Set it to your own zone, or the
digest lands at a surprising hour.
Set the digest slot
- Open Settings and find Digest delivery.
- Choose Weekly or Daily. For weekly, pick the weekday.
- Set the time and press Save schedule.
The worker re-reads the schedule every minute, so the change takes effect within a minute without
a restart. The worker logs the new slot, for example
Digest scheduled weekly on Monday at 08:00 ("0 8 * * 1", Europe/Amsterdam).
Change ingestion or cleanup
These two are environment variables. Edit .env, then restart the worker:
docker compose up -d workerAn invalid cron expression stops the worker at startup with
Invalid INGEST_CRON cron expression (or CLEANUP_CRON); check docker compose logs worker.
What happens with a missed run
The worker keeps no record of when a job last ran. A scheduled tick that fires up to 10 minutes late still runs; anything later is skipped until the next scheduled slot. There is no catch-up.
In practice:
- The host was asleep or off at the digest slot (a laptop on Sunday at 17:00): no digest that week. Press Generate digest now on the Digests page, or move the digest to a moment the machine is reliably on.
- The worker was restarted after the slot had passed: the same; the next occurrence runs normally.
- A missed ingest tick is harmless: every digest run fetches all sources first, so the digest always sees what was published since the last successful fetch.
Run it on an always-on box
A Raspberry Pi, a NAS or a small VPS that never sleeps makes this a non-issue. The image is
built for arm64 as well as amd64.
Manual runs and scheduled runs
Fetch now and Generate digest now call the same jobs as the worker, but they run inside
the app container and are fire-and-forget: the button immediately says
Started in the background; refresh in a bit., whether or not the job later succeeds. The only
evidence of a failure is docker compose logs app or a failed digest on the Digests page.
Nothing locks a manual run against a scheduled one, since they run in different containers. That
is safe in practice: a completed digest marks its items as digested, so a second run started at the
same time finds nothing left and records an empty digest.