fix(llm): honor GRAPHIFY_API_TIMEOUT in the bedrock backend - #2283
fix(llm): honor GRAPHIFY_API_TIMEOUT in the bedrock backend#2283zhiyanliu wants to merge 1 commit into
Conversation
The two bedrock-runtime clients (primary extraction in _call_bedrock and the secondary dispatch path in _call_llm) were built with no botocore config, so Converse used botocore's 60s default read timeout and ignored GRAPHIFY_API_TIMEOUT / --api-timeout entirely. A long opus-class generation then died with "Read timeout on endpoint URL" no matter how high the timeout was set. Both client constructions now pass a botocore.config.Config wiring read_timeout to _resolve_api_timeout() (default 600s), a 10s connect_timeout, and retries from _resolve_max_retries() in adaptive mode. This mirrors the fixes that closed the same gap for the claude-cli subprocess (Graphify-Labs#1112/Graphify-Labs#1111) and the secondary LLM dispatch path (Graphify-Labs#1442) -- bedrock was the last cloud backend still ignoring the knob. Also updates the README env-var row, which listed the timeout as applying to HTTP/claude-cli/Anthropic only, and the _fake_boto3 test fixture to register botocore.config and capture the client config so the new coverage can assert the timeout is wired.
There was a problem hiding this comment.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Graphify reviewed this change.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Graphify review — findings
This PR wires the GRAPHIFY_API_TIMEOUT (and retry) settings into the AWS Bedrock backend by constructing the bedrock-runtime boto3 client with an explicit botocore.config.Config (read/connect timeouts and retry policy) in both _call_bedrock and the _call_llm bedrock branch. The README's GRAPHIFY_API_TIMEOUT row is updated to mention the Bedrock backend, and the test suite's fake boto3 fixture is extended to stub botocore.config and capture client-construction kwargs, with two new tests asserting the timeout/retry values reach the client both when the env var is set and when it defaults. Surface area is limited to the Bedrock client setup in graphify/llm.py, one README table row, and the image-vision test file's boto3 fakes plus two added tests.
Worth a look
- Double retry layering: botocore retries stacked on top of application-level retry loop —
graphify/llm.py:1631· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 617 functions depend on the 212 node(s) this change touches.
Health — this change adds coupling hotspots:
- worse:
_call_bedrock()— 4 callers, 7 callees
Verification — 617 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 427 function(s) in the blast radius were not formally verified this run
· 1 more finding(s) on lines outside this diff (see the check run).
|
Thanks for the review. On the double-retry-layering note — I looked at how the application-level retry actually classifies failures, and I don't think the two layers meaningfully stack here, but wanted to lay out the evidence so a maintainer can decide. The adaptive retry in The retry policy on the Bedrock client also mirrors the existing cloud backends rather than introducing a new pattern — the OpenAI, Anthropic, and Azure clients each already pass Happy to drop the |
Summary
Both
bedrock-runtimeclients — the primary extraction path (_call_bedrock) and the secondary dispatch path (thebedrockbranch of_call_llm) — are built with no botocore config, so Converse uses botocore's 60s default read timeout and ignoresGRAPHIFY_API_TIMEOUT/--api-timeoutentirely. A long opus-class generation then dies withRead timeout on endpoint URLregardless of how high the timeout is set.This wires both client constructions through a
botocore.config.Configthat setsread_timeout=_resolve_api_timeout()(default 600s), a 10sconnect_timeout, andretriesfrom_resolve_max_retries()in adaptive mode.This mirrors the fixes that closed the same gap for the
claude-clisubprocess (#1112 / #1111) and the secondary LLM dispatch path (#1442). Bedrock was the last cloud backend still ignoring the knob, and the README env-var table already advertised the timeout as general — so the gap was easy to trip over.Root cause
session.client("bedrock-runtime")was called with noconfig=, at both sites. botocore's defaultread_timeoutis 60s, so a Converse call that generates for longer is cut off at 60s with aRead timeout on endpoint URLerror — the env var never reaches boto3.What changed
_call_bedrockand the_call_llmbedrock branch now build the client withbotocore.config.Config(read_timeout=_resolve_api_timeout(), connect_timeout=10, retries=…)._fake_boto3test fixture registersbotocore.configand captures the client config; added coverage asserting the timeout is wired (override + default) alongside the existing image-bytes test.Verification
Reproduced against a real Bedrock model (
global.anthropic.claude-opus-5): before, large doc chunks failed withRead timeout on endpoint URLunder a raisedGRAPHIFY_API_TIMEOUT; after, the value reaches boto3'sread_timeoutand the chunks complete. Added a test that intercepts client construction and assertsread_timeout == GRAPHIFY_API_TIMEOUT(and the 600s default when unset).ruff checkclean on the changed files; the full image-vision suite passes.Happy to revisit the
connect_timeout/ retry-mode choices if you'd prefer to match a different convention.Fixes #2284