fix(egress-ledger): reconnect redis indefinitely so egress-gateway self-heals - #13
Merged
Merged
Conversation
…lf-heals The egress-ledger redis client used retryStrategy returning null after 5 attempts, which puts ioredis into the terminal "end" state and stops all reconnection. If redis is briefly unreachable at startup (e.g. a transient network/policy blip), the cached singleton gives up for good; the readiness probe (/ready -> pingEgressLedger -> ping) then fails forever while /live keeps returning 200, so the pod is never restarted and never recovers. Match the capped-backoff, never-give-up strategy already used by file-server.ts and tool-call-server.ts so the client self-heals once redis becomes reachable again.
rschlaefli
marked this pull request as ready for review
July 10, 2026 09:58
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.
Problem
codeapi-egress-gatewaypods run but stay0/1(readiness never passes), which keeps theapp-codeapiArgoCD appDegraded. Observed in prd: two pods0/1for days,/readyreturning503, with the only log line beingEgress gateway readiness failedand an empty{}error (the real cause is swallowed by the logger).Root cause
redisConnection()inservice/src/egress-ledger.tscaches a singleton ioredis client and configured it with:When
retryStrategyreturnsnull, ioredis moves the connection to the terminalendstate and stops reconnecting for the lifetime of the process. If redis is briefly unreachable while the client is first created — e.g. a transient network/NetworkPolicy blip during a deploy/cutover — the singleton exhausts its 5 retries (~10s) and gives up for good.From then on:
/ready → pingEgressLedger() → redisConnection().ping()hits the dead client and rejects withConnection is closed(the empty{}in the logs) → readiness503forever./livereturns200unconditionally → liveness never fails → the pod is never restarted, so the dead singleton is never recreated. The pod is wedged until a manual restart.Confirmation
Diagnosed against the running prd pod:
enableReadyCheck: true,maxRetriesPerRequest: 1, TLS) inside the same pod returnsPING_OK PONGagainst the managed redis endpoint → redis is reachable; auth/TLS/network are fine.service-worker) connects cleanly with zero redis errors → not a reachability problem.kubectl rollout restartof the deployment immediately brought the pod to1/1andapp-codeapiback toHealthy, confirming the diagnosis.Fix
Use a capped-backoff strategy that retries indefinitely and never returns
null, so the client self-heals once redis is reachable again:This is the identical pattern already used by
service/src/file-server.tsandservice/src/tool-call-server.tsin this repo, so it aligns the egress-ledger client with its siblings rather than introducing a new convention.Individual readiness pings still fail fast during an actual outage (via
maxRetriesPerRequest: 1), which is correct — readiness should reflect real state — but the connection now recovers on its own instead of staying dead.Scope / related
service/src/queue.tshas a similar boundedretryStrategy, but the BullMQ producer/worker pods crash-loop and restart on a dead connection (they surface it through liveness), so they self-heal a different way. Left out of scope for this focused fix.Verification
kubectl rollout restart deployment/codeapi-egress-gateway(1/1, endpoint populated,app-codeapiHealthy). This change prevents the wedge from recurring on the next transient redis interruption.Manual check before merge: build the
egress-gatewayimage from this branch and confirm/readyrecovers on its own after a simulated brief redis outage (block, then unblock) without a pod restart.