mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
fix(health): attribute background health check results to their own deployment (#44982)
* fix(health): attribute background health check results to their own deployment Co-authored-by: Dennis Pfisterer <302635+pfisterer@users.noreply.github.com> Co-authored-by: Suhas Hanamannavar <hanamannavarsuhas17@gmail.com> Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(health): annotate locals with Final and split nested comprehension Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: Mubashir Osmani <mubashir@berri.ai> Co-authored-by: Dennis Pfisterer <302635+pfisterer@users.noreply.github.com> Co-authored-by: Suhas Hanamannavar <hanamannavarsuhas17@gmail.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
91e9b1f06b
commit
736ff14f11
2 changed files with 54 additions and 3 deletions
|
|
@ -730,6 +730,19 @@ def _build_model_param_to_info_mapping(model_list: list) -> dict:
|
|||
return model_param_to_info
|
||||
|
||||
|
||||
def _model_infos_for_endpoint(
|
||||
model_param_to_info: Mapping[str, list[Mapping[str, str | None]]], endpoint: Mapping[str, object]
|
||||
) -> tuple[Mapping[str, str | None], ...]:
|
||||
model_param: Final = endpoint.get("model")
|
||||
if not isinstance(model_param, str):
|
||||
return ()
|
||||
model_infos: Final = model_param_to_info.get(model_param, [])
|
||||
endpoint_model_id: Final = endpoint.get("model_id")
|
||||
if not endpoint_model_id:
|
||||
return tuple(model_infos)
|
||||
return tuple(info for info in model_infos if info["model_id"] == endpoint_model_id)
|
||||
|
||||
|
||||
def _aggregate_health_check_results(
|
||||
model_param_to_info: dict,
|
||||
healthy_endpoints: list,
|
||||
|
|
@ -754,7 +767,7 @@ def _aggregate_health_check_results(
|
|||
for endpoint in healthy_endpoints:
|
||||
model_param = endpoint.get("model")
|
||||
if model_param and model_param in model_param_to_info:
|
||||
for model_info in model_param_to_info[model_param]:
|
||||
for model_info in _model_infos_for_endpoint(model_param_to_info, endpoint):
|
||||
key = (model_info["model_id"], model_info["model_name"])
|
||||
if key not in model_results:
|
||||
model_results[key] = {
|
||||
|
|
@ -771,7 +784,7 @@ def _aggregate_health_check_results(
|
|||
model_param = endpoint.get("model")
|
||||
error_message = endpoint.get("error")
|
||||
if model_param and model_param in model_param_to_info:
|
||||
for model_info in model_param_to_info[model_param]:
|
||||
for model_info in _model_infos_for_endpoint(model_param_to_info, endpoint):
|
||||
key = (model_info["model_id"], model_info["model_name"])
|
||||
if key not in model_results:
|
||||
model_results[key] = {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import asyncio
|
||||
import time
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Final
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
from litellm.proxy._types import UserAPIKeyAuth
|
||||
from litellm.proxy.db.health_check_latest import LatestHealthCheckRow
|
||||
from litellm.proxy.health_endpoints._health_endpoints import (
|
||||
|
|
@ -220,6 +220,44 @@ def test_aggregate_health_check_results_multiple_endpoints():
|
|||
assert result[key]["unhealthy_count"] == 0
|
||||
|
||||
|
||||
def test_aggregate_health_check_results_attributes_each_result_to_its_own_deployment():
|
||||
deployments: Final = (("a", "qwen"), ("a", "qwen-alias"), ("b", "qwen"), ("b", "qwen-alias"))
|
||||
model_list: Final = [
|
||||
{
|
||||
"model_name": name,
|
||||
"litellm_params": {"model": "openai/qwen", "api_base": f"http://{host}:11434/v1"},
|
||||
"model_info": {"id": f"{host}-{name}"},
|
||||
}
|
||||
for host, name in deployments
|
||||
]
|
||||
healthy_endpoints: Final = [
|
||||
{"model": "openai/qwen", "api_base": "http://a:11434/v1", "model_id": "a-qwen"},
|
||||
{"model": "openai/qwen", "api_base": "http://a:11434/v1", "model_id": "a-qwen-alias"},
|
||||
]
|
||||
unhealthy_endpoints: Final = [
|
||||
{"model": "openai/qwen", "api_base": "http://b:11434/v1", "model_id": "b-qwen", "error": "Connection error."},
|
||||
{
|
||||
"model": "openai/qwen",
|
||||
"api_base": "http://b:11434/v1",
|
||||
"model_id": "b-qwen-alias",
|
||||
"error": "Connection error.",
|
||||
},
|
||||
]
|
||||
|
||||
result: Final = _aggregate_health_check_results(
|
||||
_build_model_param_to_info_mapping(model_list), healthy_endpoints, unhealthy_endpoints
|
||||
)
|
||||
|
||||
assert {
|
||||
key: (value["healthy_count"], value["unhealthy_count"], value["error_message"]) for key, value in result.items()
|
||||
} == {
|
||||
("a-qwen", "qwen"): (1, 0, None),
|
||||
("a-qwen-alias", "qwen-alias"): (1, 0, None),
|
||||
("b-qwen", "qwen"): (0, 1, "Connection error."),
|
||||
("b-qwen-alias", "qwen-alias"): (0, 1, "Connection error."),
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_save_health_check_results_if_changed_status_changed():
|
||||
"""Test saving when status changes"""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue