fix(cron): skip null runHistory elements when loading jobs.json

Null entries in state.runHistory raised TypeError and quarantined the
store. Skip non-dict elements like LocalTrigger.from_dict already does.
This commit is contained in:
santhreal
2026-07-23 14:07:06 +08:00
committed by chengyongru
parent 0191c0db73
commit 299bcf491b
2 changed files with 40 additions and 0 deletions
+1
View File
@@ -118,6 +118,7 @@ class CronJobState:
if isinstance(record, CronRunRecord) if isinstance(record, CronRunRecord)
else CronRunRecord.from_store_dict(record) else CronRunRecord.from_store_dict(record)
for record in history for record in history
if isinstance(record, (dict, CronRunRecord))
], ],
) )
+39
View File
@@ -1086,3 +1086,42 @@ def test_load_jobs_accepts_null_run_history_ms(tmp_path) -> None:
assert jobs[0].state.run_history[0].status == "ok" assert jobs[0].state.run_history[0].status == "ok"
assert jobs[0].created_at_ms == 0 assert jobs[0].created_at_ms == 0
assert jobs[0].updated_at_ms == 0 assert jobs[0].updated_at_ms == 0
def test_load_jobs_skips_null_run_history_elements(tmp_path) -> None:
"""Null runHistory elements must be skipped like LocalTrigger.from_dict."""
store_path = tmp_path / "cron" / "jobs.json"
store_path.parent.mkdir(parents=True)
store_path.write_text(
json.dumps(
{
"version": 1,
"jobs": [
{
"id": "j1",
"name": "t",
"enabled": True,
"schedule": {"kind": "every", "everyMs": 60_000},
"payload": {
"kind": "agent_turn",
"message": "hi",
"sessionKey": "websocket:chat-1",
},
"state": {
"runHistory": [
None,
{"runAtMs": 1, "status": "ok", "durationMs": 2},
],
},
}
],
}
),
encoding="utf-8",
)
jobs, _version = CronService(store_path)._load_jobs()
assert jobs is not None
assert len(jobs[0].state.run_history) == 1
assert jobs[0].state.run_history[0].run_at_ms == 1
assert jobs[0].state.run_history[0].status == "ok"