mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-23 00:41:40 +00:00
fix(router): allow APIConnectionError to trigger cooldown for failover
Remove APIConnectionError from the ignored_strings list in _is_cooldown_required(). The blanket exclusion prevented unreachable hosts from being cooled down, so the router retried the same dead deployment on every attempt instead of failing over to healthy ones. APIConnectionError indicates the host is unreachable -- exactly the scenario where cooldown and failover should activate. Single-deployment model groups are already protected from unnecessary cooldown by the traffic-based logic in _should_cooldown_deployment(). Fixes #27362
This commit is contained in:
parent
fa81017e12
commit
54beb8af3d
2 changed files with 91 additions and 8 deletions
|
|
@ -54,14 +54,6 @@ def _is_cooldown_required(
|
|||
bool: True if a cooldown is required, False otherwise.
|
||||
"""
|
||||
try:
|
||||
ignored_strings = ["APIConnectionError"]
|
||||
if (
|
||||
exception_str is not None
|
||||
): # don't cooldown on litellm api connection errors errors
|
||||
for ignored_string in ignored_strings:
|
||||
if ignored_string in exception_str:
|
||||
return False
|
||||
|
||||
if isinstance(exception_status, str):
|
||||
if len(exception_status) == 0:
|
||||
return False
|
||||
|
|
|
|||
91
tests/test_litellm/router_utils/test_cooldown_handlers.py
Normal file
91
tests/test_litellm/router_utils/test_cooldown_handlers.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
"""
|
||||
Unit tests for cooldown handler logic in litellm.router_utils.cooldown_handlers
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, os.path.abspath("../../.."))
|
||||
|
||||
import litellm
|
||||
from litellm.router_utils.cooldown_handlers import _is_cooldown_required
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_router():
|
||||
router = MagicMock()
|
||||
router.allowed_fails = None
|
||||
router.allowed_fails_policy = None
|
||||
return router
|
||||
|
||||
|
||||
class TestIsCooldownRequired:
|
||||
"""Tests for _is_cooldown_required behavior with connection errors."""
|
||||
|
||||
def test_api_connection_error_triggers_cooldown(self, mock_router):
|
||||
"""
|
||||
APIConnectionError (unreachable host) should trigger cooldown so the
|
||||
router can fail over to healthy deployments.
|
||||
|
||||
Regression test for https://github.com/BerriAI/litellm/issues/27362
|
||||
"""
|
||||
exception = litellm.APIConnectionError(
|
||||
message="Cannot connect to host example:11434",
|
||||
llm_provider="ollama",
|
||||
model="llama3.1:8b",
|
||||
)
|
||||
|
||||
result = _is_cooldown_required(
|
||||
litellm_router_instance=mock_router,
|
||||
model_id="test_deployment",
|
||||
exception_status=500,
|
||||
exception_str=str(exception),
|
||||
)
|
||||
|
||||
assert result is True
|
||||
|
||||
def test_server_error_triggers_cooldown(self, mock_router):
|
||||
"""500-level errors should trigger cooldown."""
|
||||
result = _is_cooldown_required(
|
||||
litellm_router_instance=mock_router,
|
||||
model_id="test_deployment",
|
||||
exception_status=500,
|
||||
exception_str="Internal Server Error",
|
||||
)
|
||||
|
||||
assert result is True
|
||||
|
||||
def test_rate_limit_triggers_cooldown(self, mock_router):
|
||||
"""429 errors should trigger cooldown."""
|
||||
result = _is_cooldown_required(
|
||||
litellm_router_instance=mock_router,
|
||||
model_id="test_deployment",
|
||||
exception_status=429,
|
||||
exception_str="Rate limit exceeded",
|
||||
)
|
||||
|
||||
assert result is True
|
||||
|
||||
def test_bad_request_does_not_trigger_cooldown(self, mock_router):
|
||||
"""400 errors (except 401, 404, 408, 429) should not trigger cooldown."""
|
||||
result = _is_cooldown_required(
|
||||
litellm_router_instance=mock_router,
|
||||
model_id="test_deployment",
|
||||
exception_status=400,
|
||||
exception_str="Bad Request",
|
||||
)
|
||||
|
||||
assert result is False
|
||||
|
||||
def test_empty_exception_status_does_not_trigger_cooldown(self, mock_router):
|
||||
"""Empty string exception status should not trigger cooldown."""
|
||||
result = _is_cooldown_required(
|
||||
litellm_router_instance=mock_router,
|
||||
model_id="test_deployment",
|
||||
exception_status="",
|
||||
)
|
||||
|
||||
assert result is False
|
||||
Loading…
Add table
Reference in a new issue