ci(llm_responses_api_testing): bound live re-record calls and rerun timeout-only failures to stop 15m no-output kills - #32420
Conversation
…imeout-only failures to stop 15m no-output kills
Greptile SummaryThis PR fixes a recurring CI flake in
Confidence Score: 5/5CI-only change with no production code touched; the two new knobs are scoped entirely to one job and correctly wired to litellm's existing REQUEST_TIMEOUT environment variable. Both mechanisms are verified in the codebase: REQUEST_TIMEOUT is read from the environment in litellm/constants.py:381 and pytest-rerunfailures 15.1 is already declared in pyproject.toml. The 180 s bound is well above observed healthy live-call times and well below the 15-minute no-output kill. No files require special attention.
|
| Filename | Overview |
|---|---|
| .circleci/config.yml | Adds REQUEST_TIMEOUT=180 job env var and --reruns 1 --only-rerun Timeout pytest flags to the llm_responses_api_testing job to bound live re-record calls and prevent silent 15-minute kills |
Reviews (1): Last reviewed commit: "ci(llm_responses_api_testing): bound liv..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…imeout-only failures to stop 15m no-output kills (BerriAI#32420)
Relevant issues
Context:
ci/circleci: llm_responses_api_testingfailed on PR #32389 at dadf926 (https://circleci.com/gh/BerriAI/litellm/2010679) even though that PR only touches Bedrock cost-map lookup ordering and the suite has zero Bedrock usage; a retrigger with no relevant change passed (https://circleci.com/gh/BerriAI/litellm/2013953), confirming a flakeLinear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito re-request a review after pushing changes)Screenshots / Proof of Fix
The failure signature, from the CircleCI step log of job 2010679: 168 of 170 tests finished within about 30 seconds of the run starting (all
[VCR HIT]cassette replays), one test started and never finished, and the step then produced zero output until CircleCI killed the jobThe same signature killed this job 6 times in the last 8 days, with 4 different tests hanging (CircleCI job number, hung test): 2010679 and 2012169 and 1993606
test_basic_openai_responses_with_websearch[False], 2004033 and 1947340test_responses_api_multi_turn_with_reasoning_and_structured_output, 2013288test_azure_responses_api.py::TestAzureResponsesAPITest::test_responses_api_shell_tool, 1960817test_gemini_3_responses_api_streaming_with_thought_signatures. So the fix targets the shared mechanism (unbounded live re-record calls), not one testBefore, captured at 4b0ac8b (origin/litellm_internal_staging). The stall itself is a rare provider-connection event, so a healthy loop passes; this establishes the baseline behavior and cost of the live call path (real OpenAI
gpt-5.5calls with theweb_searchtool, no cassette, no mocks)What happens today when that live call stalls: nothing bounds it under litellm's 6000s default request timeout, so the worker sits silent until the 15m no-output kill. Demonstrated at 4b0ac8b by forcing every live call to be slower than the bound; with
REQUEST_TIMEOUTset the stall surfaces as a visiblelitellm.Timeoutin under a second instead of silenceAfter, captured at 3271a77, same forced-stall scenario but with the new job flags; both the streaming and non-streaming variants time out fast, get rerun once, and the failure output stays visible the whole time (in a real one-off stall the rerun records on a fresh connection and passes, keeping the job green)
After, captured at 3271a77, healthy-path loop with the exact new knobs (real OpenAI calls)
And a full live (cassette-disabled) run of the OpenAI and Gemini test files with the new flags, to simulate the worst case where every cassette expired on the same day, captured at 3271a77
The 4 failures are pre-existing pure-live failures, byte-for-byte the same set on unmodified origin/litellm_internal_staging (4b0ac8b) without the new flags (they pass in CI via cassette replay), so the new knobs change nothing on healthy runs
Type
🚄 Infrastructure
Changes
This suite replays provider traffic from the Redis-backed VCR cassette cache. Cassettes expire 24 hours after their last write and the TTL is deliberately not refreshed on read (tests/_vcr_redis_persister.py), so roughly once per day each test re-records against the live provider. That re-record call runs with litellm's default request timeout of 6000 seconds (litellm/constants.py:381, applied on the responses path at litellm/responses/main.py:1109), so when the provider connection stalls (server-side web_search execution, reasoning calls, mid-stream reads) nothing client-side aborts it. Every other test finishes within a minute via cassette hits, the lone xdist worker sits silent, and CircleCI kills the whole job at
no_output_timeout: 15m. The kill also means junit.xml is never written, so the failed job reports no failing test, which is why this flake kept looking randomTwo scoped knobs on the job fix the mechanism.
REQUEST_TIMEOUT: "180"in the job environment bounds every live call at 180 seconds (cassette replays never hit the network and are unaffected; the slowest legitimate live requests in this suite run well under a minute).--reruns 1 --only-rerun Timeoutreruns only timeout-class failures once, so a one-off dead connection re-records on a fresh connection and the job stays green, while a persistent provider incident still fails the job, now within minutes and with a readablelitellm.Timeouttraceback instead of a silent 15 minute hang. The rerun is deliberately not blanket: non-timeout failures are real failures and still fail immediately