Compare commits
1 Commits
fix/913-sy
...
fix/cron-s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
943f88102d |
33
cron/jobs.py
33
cron/jobs.py
@@ -317,6 +317,21 @@ def compute_next_run(schedule: Dict[str, Any], last_run_at: Optional[str] = None
|
|||||||
# Job CRUD Operations
|
# Job CRUD Operations
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
def _normalize_job_schedules(jobs: List[Dict[str, Any]]):
|
||||||
|
"""Convert any string schedules to parsed dicts in-place."""
|
||||||
|
for job in jobs:
|
||||||
|
sched = job.get("schedule")
|
||||||
|
if isinstance(sched, str):
|
||||||
|
try:
|
||||||
|
job["schedule"] = parse_schedule(sched)
|
||||||
|
except Exception:
|
||||||
|
job["schedule"] = {"kind": "unknown", "raw": sched}
|
||||||
|
elif isinstance(sched, dict):
|
||||||
|
pass # already fine
|
||||||
|
elif sched is None:
|
||||||
|
pass # no schedule (cron-managed or paused)
|
||||||
|
|
||||||
|
|
||||||
def load_jobs() -> List[Dict[str, Any]]:
|
def load_jobs() -> List[Dict[str, Any]]:
|
||||||
"""Load all jobs from storage."""
|
"""Load all jobs from storage."""
|
||||||
ensure_dirs()
|
ensure_dirs()
|
||||||
@@ -326,13 +341,16 @@ def load_jobs() -> List[Dict[str, Any]]:
|
|||||||
try:
|
try:
|
||||||
with open(JOBS_FILE, 'r', encoding='utf-8') as f:
|
with open(JOBS_FILE, 'r', encoding='utf-8') as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
return data.get("jobs", [])
|
jobs = data.get("jobs", [])
|
||||||
|
_normalize_job_schedules(jobs)
|
||||||
|
return jobs
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
# Retry with strict=False to handle bare control chars in string values
|
# Retry with strict=False to handle bare control chars in string values
|
||||||
try:
|
try:
|
||||||
with open(JOBS_FILE, 'r', encoding='utf-8') as f:
|
with open(JOBS_FILE, 'r', encoding='utf-8') as f:
|
||||||
data = json.loads(f.read(), strict=False)
|
data = json.loads(f.read(), strict=False)
|
||||||
jobs = data.get("jobs", [])
|
jobs = data.get("jobs", [])
|
||||||
|
_normalize_job_schedules(jobs)
|
||||||
if jobs:
|
if jobs:
|
||||||
# Auto-repair: rewrite with proper escaping
|
# Auto-repair: rewrite with proper escaping
|
||||||
save_jobs(jobs)
|
save_jobs(jobs)
|
||||||
@@ -642,7 +660,13 @@ def advance_next_run(job_id: str) -> bool:
|
|||||||
jobs = load_jobs()
|
jobs = load_jobs()
|
||||||
for job in jobs:
|
for job in jobs:
|
||||||
if job["id"] == job_id:
|
if job["id"] == job_id:
|
||||||
kind = job.get("schedule", {}).get("kind")
|
schedule = job.get("schedule", {})
|
||||||
|
if isinstance(schedule, str):
|
||||||
|
try:
|
||||||
|
schedule = parse_schedule(schedule)
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
kind = schedule.get("kind")
|
||||||
if kind not in ("cron", "interval"):
|
if kind not in ("cron", "interval"):
|
||||||
return False
|
return False
|
||||||
now = _hermes_now().isoformat()
|
now = _hermes_now().isoformat()
|
||||||
@@ -699,6 +723,11 @@ def get_due_jobs() -> List[Dict[str, Any]]:
|
|||||||
next_run_dt = _ensure_aware(datetime.fromisoformat(next_run))
|
next_run_dt = _ensure_aware(datetime.fromisoformat(next_run))
|
||||||
if next_run_dt <= now:
|
if next_run_dt <= now:
|
||||||
schedule = job.get("schedule", {})
|
schedule = job.get("schedule", {})
|
||||||
|
if isinstance(schedule, str):
|
||||||
|
try:
|
||||||
|
schedule = parse_schedule(schedule)
|
||||||
|
except Exception:
|
||||||
|
schedule = {"kind": "unknown"}
|
||||||
kind = schedule.get("kind")
|
kind = schedule.get("kind")
|
||||||
|
|
||||||
# For recurring jobs, check if the scheduled time is stale
|
# For recurring jobs, check if the scheduled time is stale
|
||||||
|
|||||||
Reference in New Issue
Block a user