From 14b5915d4c74dcfc1490fb4e58caf3af42110253 Mon Sep 17 00:00:00 2001 From: mateo Date: Thu, 10 Sep 2026 21:24:29 +0000 Subject: [PATCH] fix(proxy): log the open-breaker TTL preservation fallback at debug instead of per request warning Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../hooks/parallel_request_limiter_v3.py | 9 +++++-- .../hooks/test_parallel_request_limiter_v3.py | 24 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/hooks/parallel_request_limiter_v3.py b/litellm/proxy/hooks/parallel_request_limiter_v3.py index c6c3dde4b6e..7fdc919de2c 100644 --- a/litellm/proxy/hooks/parallel_request_limiter_v3.py +++ b/litellm/proxy/hooks/parallel_request_limiter_v3.py @@ -26,6 +26,7 @@ from typing_extensions import NotRequired, ReadOnly from litellm import DualCache from litellm._logging import verbose_proxy_logger +from litellm.caching.redis_cache import RedisCircuitBreakerOpenError from litellm.constants import DYNAMIC_RATE_LIMIT_ERROR_THRESHOLD_PER_MINUTE, INTERNAL_CALL_ORIGIN_METADATA_KEY from litellm.integrations.custom_logger import CustomLogger from litellm.litellm_core_utils.prompt_templates.common_utils import ( @@ -3856,8 +3857,12 @@ class _PROXY_MaxParallelRequestsHandler_v3(CustomLogger): ) except Exception as e: - verbose_proxy_logger.warning("TTL preservation failed, falling back to regular pipeline: %s", e) - # Fallback to regular pipeline on error + log: Final = ( + verbose_proxy_logger.debug + if isinstance(e, RedisCircuitBreakerOpenError) + else verbose_proxy_logger.warning + ) + log("TTL preservation failed, falling back to regular pipeline: %s", e) await self.internal_usage_cache.dual_cache.async_increment_cache_pipeline( increment_list=pipeline_operations, litellm_parent_otel_span=parent_otel_span, diff --git a/tests/test_litellm/proxy/hooks/test_parallel_request_limiter_v3.py b/tests/test_litellm/proxy/hooks/test_parallel_request_limiter_v3.py index 6d382370f5f..2d49338753d 100644 --- a/tests/test_litellm/proxy/hooks/test_parallel_request_limiter_v3.py +++ b/tests/test_litellm/proxy/hooks/test_parallel_request_limiter_v3.py @@ -1795,6 +1795,30 @@ async def test_async_increment_tokens_fallback_behavior(): ), "Fallback method should be called when Lua script is not available" +@pytest.mark.asyncio +async def test_async_increment_tokens_open_breaker_falls_back_without_warning(caplog): + """An open Redis breaker fast-fails the Lua script on every request, so it must fall + back to the regular pipeline quietly instead of emitting a WARNING per request.""" + from unittest.mock import AsyncMock + + from litellm.caching.redis_cache import RedisCircuitBreakerOpenError + + handler = _PROXY_MaxParallelRequestsHandler(internal_usage_cache=InternalUsageCache(DualCache())) + handler.token_increment_script = object() + handler._execute_token_increment_script = AsyncMock( + side_effect=RedisCircuitBreakerOpenError("Redis circuit breaker is open, skipping run_script") + ) + fallback = AsyncMock() + handler.internal_usage_cache.dual_cache.async_increment_cache_pipeline = fallback + pipeline_operations = [RedisPipelineIncrementOperation(key="test_breaker_key", increment_value=10.0, ttl=60)] + + with caplog.at_level(logging.DEBUG, logger="LiteLLM Proxy"): + await handler.async_increment_tokens_with_ttl_preservation(pipeline_operations=pipeline_operations) + + assert fallback.await_count == 1 + assert [r.levelno for r in caplog.records if "TTL preservation failed" in r.getMessage()] == [logging.DEBUG] + + # Redis Cluster Compatibility Tests def test_group_keys_by_hash_tag_regular_redis(): """