fix(gateway): prevent parallel conversation loops on restart mid-turn - #85285
fix(gateway): prevent parallel conversation loops on restart mid-turn#85285webtecnica wants to merge 1 commit into
Conversation
|
The change looks right to me for the gateway stack. A marker with no owner on it cannot tell a resume apart from a second loop, so recording the pid that wrote the lease and refusing to start while that pid is alive is the correct shape. Before this merges with Minor, and only a suggestion: a bare pid survives recycling, so a later probe can find an unrelated process wearing the same number and refuse a resume that should have run. |
fix(gateway): prevent parallel conversation loops on restart mid-turn
|
Summary
A gateway restart mid-turn spawned two parallel conversation loops on the same session — duplicate (divergent) final responses delivered. The race is cross-process (restart detached): the new gateway comes up while the old process is still draining its turn; the old loop keeps running (making API calls, delivering the final response) while the new boot promotes the durable
active_turn_tokentoresume_pending, clears it, and spawns an auto-resume → 2 loops, 2 divergent finals. The turn lease (#64934) is process-local and doesn't see the other process.Change (fail-closed: never 2 loops on the same session)
gateway/session.py(+67): the durableactive_turn_tokenbecomes a lease with an owner — it now carries the gateway PID that wrote it (mark_turn_active); the resume path refuses to start a new loop while the owner is alive (gateway.status._pid_exists, Windows-safe, noos.kill(pid,0)).gateway/run.py(+28): resume/auto-resume consults the owner lease before spawning.tests/gateway/test_active_turn_recovery.py(+81) +test_restart_resume_pending.py(+122): owner-alive → resume refused; owner-dead → resume proceeds; restart-mid-turn → single loop.Verification
tests/gateway/test_active_turn_recovery.py+test_restart_resume_pending.py: 56 passed. Residual 1.7s overlap between detached helper launch and old-process death cannot create a 2nd loop (auto-resume refused while owner alive; bounded by drain timeout + shutdown watchdog).Closes #85207