fix(slack_alerting): poll while the deprecation alert is disabled instead of sleeping a day

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
mateo 2026-08-12 16:11:50 +00:00
parent 2278118493
commit 3f0306188a
3 changed files with 20 additions and 10 deletions

View file

@ -43,7 +43,7 @@ from litellm.repositories.user_repository import UserRepository
from litellm.types.integrations.slack_alerting import *
from litellm.types.proxy.model_deprecation import (
DEFAULT_DEPRECATION_CHECK_INTERVAL_SECONDS,
DEPRECATION_ROUTER_WAIT_SECONDS,
DEPRECATION_IDLE_POLL_SECONDS,
)
from ..email_templates.templates import *
@ -1049,9 +1049,12 @@ Model Info:
async def model_removed_alert(self, model_name: str):
pass
def _deprecation_alerts_enabled(self) -> bool:
return self.alerting is not None and AlertType.model_deprecation_warnings in self.alert_types
async def send_model_deprecation_alert(self, llm_router: Router | None = None) -> bool:
"""Alert on the router's deprecated and imminent models, True when one was sent"""
if self.alerting is None or AlertType.model_deprecation_warnings not in self.alert_types:
if not self._deprecation_alerts_enabled():
return False
from litellm.proxy.common_utils.model_deprecation import (
@ -1081,10 +1084,10 @@ Model Info:
async def _run_scheduled_deprecation_check(
self, get_llm_router: Callable[[], Router | None] = _proxy_llm_router
) -> None:
"""Alert once the router is loaded, then daily, re-reading the router and alert types each pass"""
"""Alert once the router is loaded and the alert is on, then daily, re-reading both each pass"""
while True:
if (llm_router := get_llm_router()) is None:
await asyncio.sleep(DEPRECATION_ROUTER_WAIT_SECONDS)
if (llm_router := get_llm_router()) is None or not self._deprecation_alerts_enabled():
await asyncio.sleep(DEPRECATION_IDLE_POLL_SECONDS)
continue
try:
await self.send_model_deprecation_alert(llm_router=llm_router)

View file

@ -9,7 +9,7 @@ DEFAULT_DEPRECATION_WARN_DAYS: Final = 30
DEFAULT_DEPRECATION_CHECK_INTERVAL_SECONDS: Final = 24 * 60 * 60
DEPRECATION_ROUTER_WAIT_SECONDS: Final = 30
DEPRECATION_IDLE_POLL_SECONDS: Final = 30
DeprecationStatus = Literal["upcoming", "imminent", "deprecated"]

View file

@ -15,7 +15,7 @@ from litellm.integrations.SlackAlerting.slack_alerting import SlackAlerting
from litellm.proxy._types import AlertType
from litellm.types.proxy.model_deprecation import (
DEFAULT_DEPRECATION_CHECK_INTERVAL_SECONDS,
DEPRECATION_ROUTER_WAIT_SECONDS,
DEPRECATION_IDLE_POLL_SECONDS,
)
@ -110,7 +110,7 @@ async def test_should_dispatch_high_severity_when_deprecated(monkeypatch):
async def test_should_alert_once_the_alert_type_and_router_arrive_after_startup(
monkeypatch,
):
"""The daily loop starts before config reload, so it must re-read both each pass"""
"""The loop starts before config reload, so a disabled pass must not cost a day of alerts"""
monkeypatch.setattr(
litellm,
"model_cost",
@ -127,7 +127,10 @@ async def test_should_alert_once_the_alert_type_and_router_arrive_after_startup(
]
)
async def stop_after_second_pass(_seconds):
slept: list[float] = []
async def stop_after_second_pass(seconds):
slept.append(seconds)
if alerting.alert_types == [AlertType.llm_exceptions]:
alerting.update_values(
alert_types=[AlertType.model_deprecation_warnings]
@ -145,6 +148,10 @@ async def test_should_alert_once_the_alert_type_and_router_arrive_after_startup(
):
await alerting._run_scheduled_deprecation_check(get_llm_router=lambda: router)
assert slept == [
DEPRECATION_IDLE_POLL_SECONDS,
DEFAULT_DEPRECATION_CHECK_INTERVAL_SECONDS,
]
mock_send_alert.assert_awaited_once()
assert "dead-alias" in mock_send_alert.await_args.kwargs["message"]
@ -190,7 +197,7 @@ async def test_should_wait_for_the_router_instead_of_sleeping_a_full_day(monkeyp
get_llm_router=lambda: next(routers)
)
assert slept == [DEPRECATION_ROUTER_WAIT_SECONDS] * router_absent_passes + [
assert slept == [DEPRECATION_IDLE_POLL_SECONDS] * router_absent_passes + [
DEFAULT_DEPRECATION_CHECK_INTERVAL_SECONDS
]
mock_send_alert.assert_awaited_once()