fix: prevent persistent 429 responses after model worker failures - #668
fix: prevent persistent 429 responses after model worker failures#668cyb-fox wants to merge 1 commit into
Conversation
Prevent unresolved futures from accumulating after worker failures, expose unhealthy engines as 503, and make request timeouts opt-in for deployments that need stalled-request detection. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Greptile SummaryThis PR supervises batching workers and exposes engine failures through request and health responses instead of allowing queues to grow indefinitely.
Confidence Score: 3/5The PR should not merge until accepted requests cannot escape failure completion and the timeout distinguishes a stalled worker from a healthy but slow or backlogged engine. Worker failure can race with in-flight registration and leave a request unresolved, while the optional watchdog can permanently disable an engine solely because one queued request exceeds a total-latency threshold. Files Needing Attention: libs/infinity_emb/infinity_emb/inference/batch_handler.py
|
| Filename | Overview |
|---|---|
| libs/infinity_emb/infinity_emb/inference/batch_handler.py | Adds worker supervision, in-flight failure, timeout monitoring, and result validation, but leaves a failure-registration race and conflates request latency with worker stalls. |
| libs/infinity_emb/infinity_emb/infinity_server.py | Propagates unhealthy engine state as HTTP 503 from model endpoints and the health check. |
| libs/infinity_emb/infinity_emb/engine.py | Exposes BatchHandler health through the asynchronous engine abstraction. |
| libs/infinity_emb/infinity_emb/env.py | Adds non-negative parsing for the optional request-timeout setting. |
| libs/infinity_emb/tests/unit_test/inference/test_batch_handler.py | Covers worker exceptions, permanently blocked inference, and mismatched result counts, but not concurrent registration failure or slow-progressing workers. |
Sequence Diagram
sequenceDiagram
participant R as Request
participant B as BatchHandler
participant W as Worker thread
participant H as Health callback
R->>B: schedule items
B->>B: check is_healthy()
W-->>H: stage exits
H->>H: set unhealthy and shutdown
H-->>B: fail current inflight snapshot
B->>B: register new futures
B->>B: enqueue after workers stopped
B-->>R: future remains pending
Reviews (1): Last reviewed commit: "fix: fail requests when a model worker s..." | Re-trigger Greptile
| if not self.is_healthy(): | ||
| raise EngineUnhealthyError("batching engine is unhealthy") | ||
|
|
||
| for item in new_prioqueue: | ||
| future = item.item.future | ||
| self._inflight[future] = self.loop.time() | ||
| future.add_done_callback(self._inflight.pop) |
There was a problem hiding this comment.
| oldest_request = min(self._inflight.values()) | ||
| elapsed = self.loop.time() - oldest_request | ||
| if elapsed > self._request_timeout: | ||
| self._mark_unhealthy( |
There was a problem hiding this comment.
Request latency triggers engine failure
When INFINITY_REQUEST_TIMEOUT is enabled and a request exceeds the threshold because of legitimate inference time or queue backlog, this check marks the entire engine unhealthy without determining whether workers are still producing results, causing all in-flight and subsequent requests to receive HTTP 503 until restart.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fd035c1d05
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| self._healthy = False | ||
| self._shutdown.set() | ||
|
|
||
| failure = EngineUnhealthyError(f"batching engine failed: {error}") |
There was a problem hiding this comment.
Preserve root worker errors when marking unhealthy
When a worker stage or the subscriber wraps the real exception in a generic ValueError (for example _core_batch crashed. or _subscribe_to_model crashed), interpolating only that wrapper here drops the underlying cause. In the new failure scenarios, waiting requests receive a generic EngineUnhealthyError, so the added tests that match simulated core failure or results for a batch fail and operators lose the diagnostic reason in the 503 response; unwrap/preserve the original exception when constructing the unhealthy error.
Useful? React with 👍 / 👎.
Summary
This PR fixes a failure mode where a single Infinity instance could begin
returning persistent HTTP 429 responses after a model worker failed.
HTTP 429 in Infinity is queue-based backpressure, not a per-client rate limit:
the server returns it when a model's pending input queue exceeds
INFINITY_QUEUE_SIZE(32,000 items by default).Root Cause
Before this change, an uncaught exception in a preprocessing, inference, or
postprocessing worker only terminated that background task.
Requests already accepted by the server held futures that were never completed.
The instance continued accepting requests, the in-memory priority queue grew,
and once it exceeded
INFINITY_QUEUE_SIZE, all subsequent requests for thatmodel received HTTP 429.
Restarting the instance appeared to fix the problem because it recreated the
workers and cleared the in-memory queue.
Changes
/healthreturn HTTP 503 when any loaded engine is unhealthy, allowingdeployment platforms to remove and restart the instance.
INFINITY_REQUEST_TIMEOUTdetection for workers that remainalive but stop producing results.
request futures.
INFINITY_REQUEST_TIMEOUTdefaults to0to preserve existing behavior forlong-running inference requests. Deployments that need stalled-request
detection can opt in with a value appropriate for their latency budget.
Related Issue
N/A
Checklist
Verification
python -m compileall -q libs/infinity_emb/infinity_embpasses.sentence_transformersis not installed.