fix(gateway): prevent stuck sessions with agent timeout and staleness eviction - #4653
Closed
kshitijk4poor wants to merge 1 commit into
Closed
fix(gateway): prevent stuck sessions with agent timeout and staleness eviction#4653kshitijk4poor wants to merge 1 commit into
kshitijk4poor wants to merge 1 commit into
Conversation
… eviction Two issues causing sessions to get permanently locked, requiring a gateway restart: 1. No timeout on agent execution: run_in_executor(None, run_sync) had no deadline. A hung API call (30min httpx timeout) or runaway tool locked the session indefinitely — the finally block that cleans up _running_agents never ran. Fix: wrap in asyncio.wait_for(timeout=HERMES_AGENT_TIMEOUT, default 10min). On timeout the agent is interrupted and the user gets an actionable error message. The finally block runs and unlocks the session. 2. No timeout on cron job execution: run_conversation is synchronous and blocked the cron ticker thread indefinitely. One hung cron job prevented all subsequent cron jobs from firing. Fix: run in a 1-worker ThreadPoolExecutor with future.result(timeout). On timeout the agent is interrupted and the pool is shut down with wait=False, cancel_futures=True so the ticker thread isn't blocked. Safety net: _running_agents_ts tracks when each session started. If an entry survives longer than timeout + 1min grace (e.g., a cleanup path was missed), it's auto-evicted on the next incoming message. New env vars: HERMES_AGENT_TIMEOUT (default 600s / 10min) HERMES_CRON_TIMEOUT (default 600s / 10min)
Contributor
|
Superseded by #4727 which includes this fix alongside the full reliability cluster from #4577. Credit to @kshitijk4poor. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes sessions getting permanently locked when an agent hangs, requiring a gateway restart. Also fixes hung cron jobs blocking all subsequent cron execution.
Problem
Stuck message sessions:
run_in_executor(None, run_sync)in_run_agenthad no timeout. A hung API call (httpx timeout is 30 minutes) or runaway tool locked the session indefinitely — thefinallyblock that cleans up_running_agentsnever ran. All subsequent messages for that session were routed to the interrupt/queue path and never processed.Stuck cron jobs:
agent.run_conversation(prompt)is synchronous and blocked the cron ticker thread. One hung cron job prevented all subsequent cron jobs from firing until gateway restart.Fix
Agent timeout (
gateway/run.py): Wraprun_in_executorwithasyncio.wait_for(timeout=HERMES_AGENT_TIMEOUT)(default 10min). On timeout, the agent is interrupted and the user gets an actionable error message. Thefinallyblock runs normally and unlocks the session.Staleness eviction (
gateway/run.py):_running_agents_tstracks start timestamps. When a new message arrives and finds an entry older than timeout + 1min grace, it's auto-evicted. Safety net for any cleanup path that fails.Cron timeout (
cron/scheduler.py): Runrun_conversationin a 1-workerThreadPoolExecutorwithfuture.result(timeout=HERMES_CRON_TIMEOUT)(default 10min). On timeout, the agent is interrupted and the pool is shut down withwait=False, cancel_futures=Trueso the ticker thread isn't blocked.New env vars
HERMES_AGENT_TIMEOUT600(10min)HERMES_CRON_TIMEOUT600(10min)Files changed
gateway/run.pyasyncio.wait_fortimeout,_running_agents_tsstaleness trackingcron/scheduler.pyThreadPoolExecutorwith timeout and non-blocking shutdownTest plan
pytest tests/gateway/ tests/cron/— 1932 passed, 6 failed (all pre-existing: approval flaky + whatsapp + progress emoji)