This commit is contained in:
ZXYxc 2026-09-02 09:37:44 +08:00 committed by GitHub
commit a2776825d2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 57 additions and 5 deletions

View file

@ -2526,6 +2526,10 @@ class ConfigGeneralSettings(LiteLLMPydanticObjectBase):
description="for `/models` endpoint, infers available model based on environment keys (e.g. OPENAI_API_KEY)",
)
background_health_checks: bool | None = Field(None, description="run health checks in background")
persist_background_health_check_results: bool = Field(
True,
description="persist background health check results to the database",
)
health_check_interval: int = Field(300, description="background health check interval in seconds")
health_check_concurrency: int | None = Field(
None,

View file

@ -3580,9 +3580,10 @@ def _schedule_background_health_check_db_save(
model_list: list,
healthy_endpoints: list,
unhealthy_endpoints: list,
persist_results: bool = True,
):
"""Fire-and-forget: persist health check results to DB if prisma is available."""
if prisma_client is None:
if prisma_client is None or not persist_results:
return
import time as time_module
@ -3764,11 +3765,12 @@ async def _run_background_health_check():
)
background_health_check_loop_active = True
verbose_proxy_logger.info(
"background_health_check_loop_started interval_seconds=%s max_concurrency=%s shared=%s details=%s thread_count=%d rss_mb=%s",
"background_health_check_loop_started interval_seconds=%s max_concurrency=%s shared=%s details=%s persist_results=%s thread_count=%d rss_mb=%s",
health_check_interval,
health_check_concurrency,
use_shared_health_check,
health_check_details,
general_settings.get("persist_background_health_check_results", True),
threading.active_count(),
_rss_mb_for_log(),
)
@ -3908,6 +3910,7 @@ async def _run_background_health_check():
_llm_model_list,
healthy_endpoints,
unhealthy_endpoints,
persist_results=general_settings.get("persist_background_health_check_results", True),
)
# Write health state to router cache for health-check-driven routing

View file

@ -19,14 +19,15 @@ from unittest.mock import AsyncMock, MagicMock
import pytest
import litellm.proxy.proxy_server as proxy_server
from litellm.proxy import proxy_server
from litellm.proxy._types import ConfigGeneralSettings
from litellm.proxy.proxy_server import (
_adaptive_router_flusher_loop,
_get_endpoint_exception_status,
_get_process_rss_mb,
_rss_mb_for_log,
_run_background_health_check,
_run_direct_health_check_with_instrumentation,
_rss_mb_for_log,
_schedule_background_health_check_db_save,
_write_health_state_to_router_cache,
)
@ -159,6 +160,18 @@ async def test_run_direct_health_check_raises_non_kwarg_typeerror(monkeypatch):
# ---------------------------------------------------------------------------
def test_background_health_check_db_persistence_config_defaults_enabled():
assert ConfigGeneralSettings().persist_background_health_check_results is True
def test_background_health_check_db_persistence_config_can_be_disabled():
settings = ConfigGeneralSettings.model_validate(
{"persist_background_health_check_results": False}
)
assert settings.persist_background_health_check_results is False
@pytest.mark.asyncio
async def test_schedule_background_health_check_db_save_creates_task(monkeypatch):
captured = {}
@ -219,6 +232,24 @@ def test_schedule_background_health_check_db_save_noop_when_prisma_none():
)
def test_schedule_background_health_check_db_save_noop_when_persistence_disabled(
monkeypatch,
):
create_task = MagicMock()
monkeypatch.setattr(asyncio, "create_task", create_task)
_schedule_background_health_check_db_save(
prisma_client=MagicMock(),
shared_health_manager=None,
model_list=[],
healthy_endpoints=[],
unhealthy_endpoints=[],
persist_results=False,
)
create_task.assert_not_called()
@pytest.mark.asyncio
async def test_schedule_background_health_check_db_save_invalid_no_event_loop_raises(
monkeypatch,
@ -527,6 +558,11 @@ async def test_run_background_health_check_runs_one_cycle_then_cancels(monkeypat
monkeypatch.setattr(proxy_server, "use_shared_health_check", False)
monkeypatch.setattr(proxy_server, "redis_usage_cache", None)
monkeypatch.setattr(proxy_server, "prisma_client", None)
monkeypatch.setattr(
proxy_server,
"general_settings",
{"persist_background_health_check_results": False},
)
monkeypatch.setattr(proxy_server, "background_health_check_loop_active", False)
monkeypatch.setattr(
proxy_server,
@ -547,8 +583,9 @@ async def test_run_background_health_check_runs_one_cycle_then_cancels(monkeypat
"_run_direct_health_check_with_instrumentation",
_fake_direct,
)
scheduled = MagicMock()
monkeypatch.setattr(
proxy_server, "_schedule_background_health_check_db_save", lambda *a, **kw: None
proxy_server, "_schedule_background_health_check_db_save", scheduled
)
monkeypatch.setattr(
proxy_server, "_write_health_state_to_router_cache", lambda *a, **kw: None
@ -574,11 +611,13 @@ async def test_run_background_health_check_runs_one_cycle_then_cancels(monkeypat
{
"healthy_count": proxy_server.health_check_results["healthy_count"],
"unhealthy_count": proxy_server.health_check_results["unhealthy_count"],
"persist_results": scheduled.call_args.kwargs["persist_results"],
"sleep_invoked": sleep_calls["n"] >= 1,
}
) == {
"healthy_count": 1,
"unhealthy_count": 1,
"persist_results": False,
"sleep_invoked": True,
}

View file

@ -25663,6 +25663,12 @@ export interface components {
* @description Default upstream request timeout in seconds for native and custom pass-through endpoints that use pass_through_request. Defaults to 600 when unset.
*/
pass_through_request_timeout?: number | null;
/**
* Persist Background Health Check Results
* @description persist background health check results to the database
* @default true
*/
persist_background_health_check_results: boolean;
/**
* Plugins
* @description external services registered as embeddable UI plugins