fix(redis): open the circuit breaker on RedisClusterException so a dead cluster cannot hang the worker - #36804
Conversation
… cluster cannot hang the worker redis-py wraps CLUSTER SLOTS connect timeouts as RedisClusterException (subclasses Exception, not TimeoutError). The circuit breaker ignored them, so every cache write retried an unreachable ElastiCache node and the 2026-08-13 staging e2e suite died on 60s ALB read timeouts. Count that exception as unhealthy, and apply fail-fast reconnect defaults (connect timeout, keepalive, health check) on both sync and async RedisCluster clients.
Greptile SummaryThe PR makes dead Redis Cluster connections fail fast without treating all cluster exceptions as health failures.
Confidence Score: 5/5The PR appears safe to merge. The previous broad exception-classification defect is resolved, and no blocking failure remains.
|
| Filename | Overview |
|---|---|
| litellm/_redis.py | Centralizes Redis Cluster reconnect defaults and applies them to both synchronous and asynchronous clients without leaving a blocking issue related to the prior thread. |
| litellm/caching/redis_cache.py | Replaces the broad RedisClusterException classification with cause-chain and unreachable-startup detection, resolving the previously reported false-positive breaker behavior. |
| tests/test_litellm/caching/test_redis_cache.py | Adds coverage proving non-connectivity cluster exceptions do not open the breaker while wrapped and message-only startup connectivity failures do. |
| tests/test_litellm/test_redis.py | Verifies reconnect defaults and explicit override behavior across synchronous and asynchronous Redis Cluster clients. |
Reviews (2): Last reviewed commit: "fix(redis): do not treat RedisClusterExc..." | Re-trigger Greptile
…down SlotNotCoveredError, CrossSlotTransactionError, and InvalidPipelineStack share that base but are command/slot/pipeline errors on a live cluster. Matching isinstance(RedisClusterException) opened the breaker and dropped shared cache and rate limits to per-process state. Detect the 2026-08-13 hang by walking __cause__ (redis-py raises RedisClusterException from TimeoutError) and the unreachable-node message when the cause is stripped.
|
Addressed the base-class match:
Tests: subclass counter-examples plus the production connect-timeout wrap; 12 passed / 2 skipped (those two subclass names are absent on this redis-py). |
PR overviewAll previously flagged issues have been addressed. No open security concerns remain on this pull request. Security reviewNo open security issues remain on this pull request. Fixed/addressed: 1 · PR risk: 0/10 |
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 7ee0b70. Configure here.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
…probe Fail-fast skips Redis while the cluster is down, but the next probe must not reuse the wedged NodesManager that hung on CLUSTER SLOTS. Evict the cached async client (and rebuild the sync one) when the breaker opens and again when the recovery probe starts, so ElastiCache coming back can accept traffic again.
|
Follow-up on this PR: fail-fast now also lets Redis come back. When the breaker opens, and again when it enters HALF_OPEN, we drop the cached HTTP traffic still fail-opens (in-memory) while OPEN. After |
9e23700 to
0f66803
Compare
TLDR
Problem this solves:
How it solves it:
User Flow
Before: a caller whose proxy uses ElastiCache Serverless (cluster mode) hits a node that is not answering, and every request hangs until their client times out
After: the same dead cluster fails fast; the proxy keeps answering
Relevant issues
Staging e2e 2026-08-13 (
litellm-e2e-1-0-0-main-20260813122400-h6rhc, rev09889e1986faa7b97d1d213040aa442b2aa393f6): 72 failed, 442 passed, 57 skipped in 13105.79s. Every captured traceback wasRead timed out. (read timeout=60.0)againstinternal-k8s-litellm-litellm-e7f4afb143-1355079179.us-east-1.elb.amazonaws.com. Gateway/backend logs after the window still showedRedis Cluster cannot be connected … Timeout connecting to serverwith zerocircuit breaker OPENEDlines.Follows the hole left by #35273 / #31577 (LIT-4083): those covered TimeoutError/ConnectionError and async reconnect defaults, not RedisClusterException or the sync cluster client.
Linear ticket
Pre-Submission checklist
@greptileaito re-request a review after pushing changes)Screenshots / Proof of Fix
Unit proof at
342cdf628e(this commit), twice:10 passed in 0.56s. The new test constructs the production exception text (
Redis Cluster cannot be connected … Timeout connecting to server), asserts it is a health failure, opens the breaker, and asserts the next call is skipped immediately.A full staging e2e re-run is not in this PR. Redis itself was still unreachable on stage after the suite; this change only stops that from freezing the worker.
Type
🐛 Bug Fix
Caveats (if any)
Final Attestation
Note
Cursor Bugbot is generating a summary for commit 7ee0b70. Configure here.