[proxy 10/13] resilience.py: retry with backoff + fallback chain #14
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Spec: this implements ONE small step of #2 (the locked reliability-proxy build, aosh leg 04). Do not redesign. Stay tightly scoped to this single step.
Before you start:
git checkout main && git pullso you build on the latest landed step.Extend
app/resilience.pywith retry and fallback. Build on step 09's validation.dispatch_resilient(logical_name, messages): callupstream.dispatch_chat+validate_response; on failure RETRY up to N times (default 3) with exponential backoff. Incrementapp.obs.llm_retries_totalper retry.app.obs.llm_fallbacks_totalper fallback. (For now a single-entry chain is fine - just wire the mechanism.)dispatch_resilientinstead of calling upstream directly.Acceptance: pytests with a monkeypatched upstream that fails twice then succeeds -> result returned,
llm_retries_totalincremented; a backend that always fails -> falls back / surfaces a clean error.When done:
pre-commit run --all-files(or the repo's gate) must pass, commit your work, and push to canonicalmain(this is an ephemeral feature container - finish the merge, do not leave it for a human).docs/FEATURES.mdfromplannedtolandedfor this feature, in the same push.ward agent engineer coilyco-flight-deck/agent-proxy#15 --driver goose🔒 Reserved by
ward agent --driver claude— containerengineer-claude-agent-proxy-14on hostkais-macbook-pro-2.localis carrying this issue (reserved 2026-07-02T16:45:50Z). Concurrentward agentruns are blocked until it finishes or the reservation goes stale (2h0m0s TTL);--forceoverrides.— Claude (she/her), via
ward agentWARD-OUTCOME: done -
dispatch_resilient(logical_name, messages)landed on main with retry/fallback acceptance tests; also fixed a latent OTel attempt-span leak the tests surfaced. Gate green (58 passed).This one turned out to be more "finish and verify" than "build": the resilience engine (
dispatch, with retry-backoff, fallback chain, circuit breaker, and step-09 validation) had already landed as part of the resilience-core chunk, and the worker already routed through it. So the honest gap for this step was the spec'd name-based entry point, which didn't exist, plus the acceptance tests the issue actually asks for, which were genuinely missing. I addeddispatch_resilientas a thin adapter over the existing engine rather than redesigning anything.What fought back: writing the acceptance tests immediately surfaced a real bug I didn't expect. The per-attempt OTel span was only closed on the success and validation-terminal paths, so every retry or fallback leaked its context token, and the next attempt's detach crashed with "token created in a different Context" whenever a tracer was active - i.e. any deploy with opentelemetry installed. It had been latent since the observability instrumentation landed because no prior test exercised retries under a live tracer. Moved the span close into a
finally, which fixed it cleanly.The other thing that fought back was the box itself: the shared host disk was pegged at 100% for the first several minutes (couldn't even build a venv), then a sibling container freed ~5G and the full suite ran fine. Confidence in the code is high - 58 tests pass on the merged-with-latest-main tree, and the change is additive and low-blast-radius.
Rough edges / follow-ups: (1) the automatic dispatch of the next step (#15) failed - this nested container has no Docker daemon, so
ward agentcan't spawn a sibling here; #15 will need to be kicked off from a host that can. (2) Worth considering whether the worker should route throughdispatch_resilientby name for consistency, but it already holds a resolvedLogicalModelfrom the route's 404 guard, so re-resolving would be a small regression - I left it calling the engine directly on purpose.— Claude (she/her), via ward agent