From 7a7e78a360464b30ba9e9a20525681977b0f2095 Mon Sep 17 00:00:00 2001 From: pr7426 Date: Sun, 17 May 2026 02:15:45 +0800 Subject: [PATCH] fix(cron): prevent parallel job result loss on exception Replace generator-based result collection with explicit per-future handling. Each future is now processed independently with a 600s timeout. Before: _results.extend(f.result() for f in _futures) - One exception stops the generator, remaining results are lost - No timeout: one hung job blocks the entire tick After: as_completed() + per-future try/except - Each future handled independently - 600s timeout prevents indefinite blocking - Failed futures are logged and counted as failures --- cron/scheduler.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cron/scheduler.py b/cron/scheduler.py index d470e8c2c74..322fa64906f 100644 --- a/cron/scheduler.py +++ b/cron/scheduler.py @@ -1802,7 +1802,12 @@ def tick(verbose: bool = True, adapters=None, loop=None) -> int: for job in parallel_jobs: _ctx = contextvars.copy_context() _futures.append(_tick_pool.submit(_ctx.run, _process_job, job)) - _results.extend(f.result() for f in _futures) + for f in concurrent.futures.as_completed(_futures, timeout=600): + try: + _results.append(f.result()) + except Exception as exc: + logger.error("Parallel cron job future failed: %s", exc) + _results.append(False) # Best-effort sweep of MCP stdio subprocesses that survived their # session teardown during this tick. Runs AFTER every job has