fix(cron): guard None repeat.completed when recording a job run
`repeat.get("completed", 0)` only falls back to 0 when the KEY is
absent. When the key exists with value None (a job created but never
successfully recorded a run), it returns None, and the following
`completed += 1` raises:
unsupported operand type(s) for +=: 'NoneType' and 'int'
Effect: the run is never recorded (last_run_at/last_status stay null)
and every fire logs a scheduling error. The job itself executes fine.
Same latent hazard at the `completed < times` comparison, which a None
value would also fail on.
Fix all three sibling sites with `repeat.get("completed") or 0`.
(cherry picked from commit 0c5024de901900a747849ca44750327b56477f3b)
This commit is contained in:
@@ -2360,7 +2360,7 @@ def _advance_after_run(job: Dict[str, Any], now: str) -> None:
|
||||
if repeat:
|
||||
times = repeat.get("times")
|
||||
finite = times is not None and times > 0
|
||||
completed = repeat.get("completed", 0)
|
||||
completed = repeat.get("completed") or 0
|
||||
# Finite one-shots were pre-claimed by claim_dispatch() (completed already incremented) —
|
||||
# do not double-count; recurring jobs and direct callers still get the increment.
|
||||
if not (kind == "once" and finite and completed > 0):
|
||||
@@ -2541,7 +2541,7 @@ def claim_dispatch(job_id: str) -> bool:
|
||||
# Recurring jobs use advance_next_run(); no/infinite repeat limit always dispatches.
|
||||
if job.get("schedule", {}).get("kind") != "once" or times is None or times <= 0:
|
||||
return True
|
||||
completed = repeat.get("completed", 0)
|
||||
completed = repeat.get("completed") or 0
|
||||
label = job.get("name", job.get("id", "?"))
|
||||
if completed >= times:
|
||||
if job.get("last_run_at") is not None:
|
||||
@@ -3098,7 +3098,7 @@ def _oneshot_dispatch_limit_reached(job: Dict[str, Any], scan: _DueScan) -> bool
|
||||
process is still running it (a run outliving the run_claim TTL is slow, not stale)."""
|
||||
repeat = job.get("repeat") or {}
|
||||
times = repeat.get("times")
|
||||
completed = repeat.get("completed", 0)
|
||||
completed = repeat.get("completed") or 0
|
||||
if times is None or times <= 0 or completed < times:
|
||||
return False
|
||||
name = job.get("name", job.get("id", "?"))
|
||||
|
||||
Reference in New Issue
Block a user