Severity: P2 — a schedule whose next-run computation fails re-executes its workflow on every tick, and its stats never persist.
Root cause
pyworkflow/primitives/schedule.py, trigger_schedule:
:413 — start() executes the workflow
:423-424 — stats (total_runs, last_run_at) updated in memory
:425 — calculate_next_run_time(...) — can raise (bad cron)
:426 — update_schedule(...) — persists; never reached on raise
So the workflow has already run, but nothing is persisted: next_run_time never advances and total_runs/last_run_at stay stale. On the next poll the schedule is still "due" → the workflow runs again. Every tick.
Executed evidence (deterministic, v0.3.8)
Schedule with an on-disk cron that fails next-run computation; two tick_once() calls:
WORKFLOW_RUNS_CREATED=2 # executed on both ticks
PERSISTED total_runs=0 last_run_at=None
next_run_time: never advanced
In a 70 s scheduler run the same setup produced 14 stray completed workflow runs.
Suggested fix
Compute the next run time (or at least validate the spec) before starting the workflow, and persist stats even when next-run computation fails (e.g. pause/error the schedule instead of leaving it perpetually due).
Severity: P2 — a schedule whose next-run computation fails re-executes its workflow on every tick, and its stats never persist.
Root cause
pyworkflow/primitives/schedule.py,trigger_schedule::413—start()executes the workflow:423-424— stats (total_runs,last_run_at) updated in memory:425—calculate_next_run_time(...)— can raise (bad cron):426—update_schedule(...)— persists; never reached on raiseSo the workflow has already run, but nothing is persisted:
next_run_timenever advances andtotal_runs/last_run_atstay stale. On the next poll the schedule is still "due" → the workflow runs again. Every tick.Executed evidence (deterministic, v0.3.8)
Schedule with an on-disk cron that fails next-run computation; two
tick_once()calls:In a 70 s scheduler run the same setup produced 14 stray completed workflow runs.
Suggested fix
Compute the next run time (or at least validate the spec) before starting the workflow, and persist stats even when next-run computation fails (e.g. pause/error the schedule instead of leaving it perpetually due).