fix(cron): coerce string schedule/state ms fields from jobs.json

jobs.json can store everyMs/atMs and next/last run timestamps as strings.
Loading left them as str, so _compute_next_run compared str to int and raised TypeError.
Coerce with an optional-int helper at from_store_dict, matching runHistory int() paths.
This commit is contained in:
santhreal
2026-07-21 19:07:45 +08:00
committed by Xubin Ren
parent 1d7bad3909
commit b81c05581f
2 changed files with 47 additions and 5 deletions
+38
View File
@@ -65,6 +65,44 @@ def test_load_jobs_accepts_snake_case_schedule_and_run_history(tmp_path) -> None
assert jobs[0].state.run_history[0].duration_ms == 12
def test_load_jobs_coerces_string_schedule_and_state_ms(tmp_path) -> None:
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": "60000"},
"payload": {
"kind": "agent_turn",
"message": "hi",
"sessionKey": "websocket:chat-1",
},
"state": {
"nextRunAtMs": "100",
"lastRunAtMs": "50",
},
"createdAtMs": 0,
"updatedAtMs": 0,
}
],
}
),
encoding="utf-8",
)
jobs, _version = CronService(store_path)._load_jobs()
assert jobs is not None
assert jobs[0].schedule.every_ms == 60_000
assert jobs[0].state.next_run_at_ms == 100
assert jobs[0].state.last_run_at_ms == 50
def test_add_job_rejects_unknown_timezone(tmp_path) -> None:
service = CronService(tmp_path / "cron" / "jobs.json")