diff --git a/litellm/integrations/SlackAlerting/slack_alerting.py b/litellm/integrations/SlackAlerting/slack_alerting.py index 82c2b4b38ce..c49b1f17d72 100644 --- a/litellm/integrations/SlackAlerting/slack_alerting.py +++ b/litellm/integrations/SlackAlerting/slack_alerting.py @@ -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) diff --git a/litellm/types/proxy/model_deprecation.py b/litellm/types/proxy/model_deprecation.py index c51c3629693..bbad63a278d 100644 --- a/litellm/types/proxy/model_deprecation.py +++ b/litellm/types/proxy/model_deprecation.py @@ -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"] diff --git a/tests/test_litellm/integrations/SlackAlerting/test_model_deprecation_alert.py b/tests/test_litellm/integrations/SlackAlerting/test_model_deprecation_alert.py index 7bdd980f00a..6dfdf831fa7 100644 --- a/tests/test_litellm/integrations/SlackAlerting/test_model_deprecation_alert.py +++ b/tests/test_litellm/integrations/SlackAlerting/test_model_deprecation_alert.py @@ -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()