thankful-pilot-45748
07/27/2026, 9:42 PMOpenHands/automation and would like guidance on the intended semantics before preparing a patch.
dispatch_pending_runs() starts each run through an untracked:
asyncio.create_task(
_execute_run_safe(...),
name=f"execute-run-{run.id}",
)
The tasks are not retained, awaited, or cancelled. During shutdown, dispatcher_loop() exits and closes its shared httpx.AsyncClient, while the application lifespan waits only for the scheduler, dispatcher, and watchdog tasks before disposing the database engine.
A controlled local test demonstrates that an execute-run-* task can still be active after the dispatcher has exited, with its shared HTTP client already closed. A run that was marked RUNNING before that point can remain in that state until later watchdog recovery.
I reproduced the lifecycle behavior deterministically using SQLite and controlled async events, without network, LLM, or sandbox dependencies.
Before implementing anything, could you clarify the desired shutdown contract?
1. Should graceful shutdown wait for all in-flight dispatch tasks?
2. If they exceed the shutdown timeout, should they be cancelled?
3. What status should be persisted for a run interrupted before dispatch completion: FAILED, restored to PENDING, or another state?
The smallest implementation appears to be a dispatcher-owned task registry with bounded draining during shutdown, but I do not want to encode cancellation or run-status semantics without maintainer guidance.quick-window-91705
07/28/2026, 2:19 AMquick-window-91705
07/28/2026, 2:20 AM