Skip to content

fix: add scheduler daemon mode to handle missed cron jobs after system wake-from-sleep#1180

Open
Jefsky wants to merge 1 commit into
sansan0:masterfrom
Jefsky:fix/scheduler-daemon-catchup
Open

fix: add scheduler daemon mode to handle missed cron jobs after system wake-from-sleep#1180
Jefsky wants to merge 1 commit into
sansan0:masterfrom
Jefsky:fix/scheduler-daemon-catchup

Conversation

@Jefsky

@Jefsky Jefsky commented Jun 27, 2026

Copy link
Copy Markdown

Problem

When running TrendRadar in Docker with RUN_MODE=cron (the default), scheduled tasks rely on supercronic to fire python -m trendradar at the configured CRON_SCHEDULE times. This works fine as long as the host system stays awake.

If the host enters sleep/hibernation (laptop lid close, standby, etc.), supercronic does not fire jobs that were scheduled during the sleep period. When the system wakes up:

  • The 11:00 scheduled run is simply skipped
  • The user must manually docker restart the container
  • After restart, the next scheduled time (e.g., 15:00) works again

This affects users on laptops (Mac/Windows/Linux) who use Docker Desktop or put their machines to sleep overnight.

Root Cause

supercronic (like all standard cron implementations) only fires jobs at their exact scheduled moment. There is no catch-up mechanism for missed jobs — the scheduling event is ephemeral.

Fix

Add a new RUN_MODE=daemon mode that replaces supercronic with a lightweight persistent Python scheduler daemon (docker/scheduler_daemon.py).

The daemon:

  1. Parses the standard CRON_SCHEDULE expression (e.g., 0 11,15 * * *)
  2. Runs a main loop that checks the time every 60 seconds
  3. Fires TrendRadar at the scheduled times with deduplication
  4. On startup, checks if any scheduled runs were missed within the last 2 hours and runs catch-up immediately — this handles wake-from-sleep
  5. During runtime, continuously monitors for missed runs and catches up
  6. Runs in parallel with the existing Web server (both start in the entrypoint)

How to use

Set the environment variable in your docker-compose.yml or Docker run command:

environment:
  RUN_MODE: daemon          # replaces the default "cron" mode
  CRON_SCHEDULE: "0 11,15 * * *"
  IMMEDIATE_RUN: "true"     # optional: run once on startup too

Testing

  1. Deploy with RUN_MODE=daemon and CRON_SCHEDULE=0 11,15 * * *
  2. Let it run and confirm scheduled execution at 11:00 and 15:00
  3. Put the host system to sleep 10 minutes before a scheduled time
  4. Wake the system after the scheduled time has passed
  5. Observe that TrendRadar runs the catch-up immediately on wake
  6. Check container logs for "[daemon] System wake-from-sleep detected: N missed run(s)"

Fixes #893

…m wake-from-sleep

Problem: When running in Docker (supercronic mode), if the host system
enters sleep/hibernation, supercronic does not fire cron jobs that were
scheduled during the sleep period. Users must manually restart the
container to trigger execution.

Root cause: supercronic (like all cron implementations) only fires jobs
at their exact scheduled time. Jobs scheduled while the system is asleep
are simply skipped with no catch-up mechanism.

Fix: Add a new RUN_MODE=daemon mode that replaces supercronic with a
persistent Python scheduler daemon (docker/scheduler_daemon.py). The
daemon:
1. Reads the CRON_SCHEDULE expression and checks every 60 seconds
2. Runs TrendRadar at scheduled times with proper deduplication
3. On startup, checks if any scheduled runs were missed during system
   sleep (up to 2 hours back) and runs catch-up immediately
4. During runtime, detects missed runs after wake events and catches up
5. Works alongside the existing Web server (started in parallel)

Usage: Set RUN_MODE=daemon (instead of default 'cron') in docker-compose.

Fixes sansan0#893
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants