diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index e3bf5949c4a..af51a05f782 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -7649,10 +7649,14 @@ class ProxyConfig: self.settings.get("maximum_spend_logs_cleanup_cron"), self.settings.get("maximum_spend_logs_retention_interval"), ) - job_missing: Final = wants_job and not has_job and attempt != self._last_cleanup_schedule_attempt - if previous_retention_values != resolved or job_missing or (has_job and not wants_job): + last_attempt: Final = self._last_cleanup_schedule_attempt + schedule_changed: Final = last_attempt is not None and attempt != last_attempt + job_missing: Final = wants_job and not has_job and attempt != last_attempt + if previous_retention_values != resolved or schedule_changed or job_missing or (has_job and not wants_job): self._last_cleanup_schedule_attempt = attempt await self._reschedule_spend_log_cleanup_job() + elif last_attempt is None: + self._last_cleanup_schedule_attempt = attempt async def _apply_ssrf_settings(self, db_values: Mapping[str, SettingsJsonValue]) -> None: _apply_ssrf_general_settings(db_values) diff --git a/tests/test_litellm/proxy/proxy_server/test_proxy_config.py b/tests/test_litellm/proxy/proxy_server/test_proxy_config.py index 33403915635..ab7803d28a6 100644 --- a/tests/test_litellm/proxy/proxy_server/test_proxy_config.py +++ b/tests/test_litellm/proxy/proxy_server/test_proxy_config.py @@ -3940,6 +3940,28 @@ async def test_ProxyConfig__update_general_settings_retries_a_failed_schedule_on assert fake_scheduler.add_job.call_args.kwargs["id"] == "spend_log_cleanup_job" +@pytest.mark.asyncio +async def test_ProxyConfig__update_general_settings_reschedules_when_only_the_cron_changes(monkeypatch): + fake_scheduler = MagicMock() + fake_scheduler.get_job.return_value = MagicMock() + monkeypatch.setattr("litellm.proxy.proxy_server.scheduler", fake_scheduler) + monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", None) + pc = ProxyConfig() + hourly = {"maximum_daily_tag_spend_retention_period": "90d", "maximum_spend_logs_cleanup_cron": "0 * * * *"} + pc.settings.apply_db_row("general_settings", hourly) + monkeypatch.setattr("litellm.proxy.proxy_server.general_settings", pc.settings) + await pc._update_general_settings(hourly) + await pc._update_general_settings(hourly) + assert fake_scheduler.add_job.call_count == 0 + + daily = {**hourly, "maximum_spend_logs_cleanup_cron": "0 3 * * *"} + pc.settings.apply_db_row("general_settings", daily) + await pc._update_general_settings(daily) + assert fake_scheduler.add_job.call_count == 1 + assert fake_scheduler.add_job.call_args.kwargs["id"] == "spend_log_cleanup_job" + assert "hour='3'" in str(fake_scheduler.add_job.call_args.args[1]) + + # --------------------------------------------------------------------------- # ProxyConfig._update_general_settings # ---------------------------------------------------------------------------