R-3: Model-server crash recovery — respawn, fast-fail gate, local fallback#145
Merged
Conversation
The shared model-server process (AUTOPTZ_MODEL_SERVER=1) was spawn-once with no recovery: a dead server meant every camera's detect() blocked its full 5s timeout forever. Add supervisor-side respawn on the same health-scan cadence, reusing the existing per-camera backoff pattern (exponential 1->30s, max 5 attempts) for the single shared process. Reuses the same request/response queues across a respawn (shm re-attach was already lazy per-request in serve(), pinned with a test rather than changed). Client-side: InferenceClient's default timeout drops 5.0s -> 2.0s and gains a server_down gate so detect() fails fast during an outage instead of stalling each camera at the full timeout per frame. On restart-budget exhaustion, Supervisor.model_server_failed() latches and every model-server-mode worker's refresh_detector_from_pool() is invoked; RemotePool.detector() now checks a failed flag and swaps in a lazily-built local detector instead of the dead IPC client, so detection continues in degraded per-worker mode. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
_respawn_model_server() previously did proc.start() then a synchronous ready.wait(timeout=30.0) inside _scan_model_server_health(), which tick() drives from a QTimer on the GUI thread — a slow respawn could freeze the UI for up to 30s per attempt, up to 5 attempts. Split the respawn into two phases across scan ticks: starting the child now only records a spawn deadline and the ready Event, returning immediately. Later ticks poll ready.is_set() (never .wait() with a timeout) until either it signals ready (success — gate cleared, attempts reset) or the deadline passes (treated as a failed attempt — stuck child killed, existing backoff/budget accounting applies). The server_down gate stays set for the whole spawning+backoff window so clients keep fast-failing throughout. Also add a real-behavior companion to test_default_timeout_is_two_seconds and simplify an existing conditional-then-reassign in the health scan. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1d39284 to
70fccba
Compare
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
The opt-in shared-detector process (
AUTOPTZ_MODEL_SERVER=1— the validated 4-12-cam scaling mode) was spawn-once: if it died, everyInferenceClient.detect()blocked 5 s and returned[]forever. Now:ready.wait(30)would have frozen the Qt main thread up to 30 s per attempt; fixed with RED/GREEN evidence, independently reproduced by the re-reviewer).timeout_s5→2 s default + aserver_downgate that returns[]immediately during outages (no 2 s/frame crawl); gate stays set through spawning+backoff, cleared on ready.model_server_failed()accessor (mirrorsis_camera_failed()) + workers rebuild LOCAL detectors viaRemotePool.detector()fallback, so detection continues degraded instead of dying.Test plan
Validation
CI-safe (opt-in path). Live mid-run server-kill exercise folds into the 2.2.0 soak gate. Includes the #141 test-isolation cherry-pick (dedupes on merge).
🤖 Generated with Claude Code