mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-12 08:42:18 +00:00
fix(alerts): stop detecting traffic drops (#51338)
This commit is contained in:
parent
61944def17
commit
6a98d09261
5 changed files with 26 additions and 44 deletions
|
|
@ -17,8 +17,6 @@ SPEND_MULTIPLIER: Final = 3
|
|||
SPEND_MIN_INCREASE_USD: Final = 50
|
||||
TRAFFIC_SPIKE_MULTIPLIER: Final = 10
|
||||
TRAFFIC_SPIKE_MIN_INCREASE: Final = 1000
|
||||
TRAFFIC_DROP_RATIO: Final = 0.2
|
||||
TRAFFIC_DROP_MIN_BASELINE: Final = 500
|
||||
LATENCY_MULTIPLIER: Final = 3
|
||||
LATENCY_MIN_INCREASE_MS: Final = 500
|
||||
LATENCY_MIN_TIMED_REQUESTS: Final = 100
|
||||
|
|
@ -45,7 +43,6 @@ class ResourceWindow(BaseModel):
|
|||
base_timed: int = Field(ge=0, le=MAX_ALERT_ID)
|
||||
active_days: int = Field(ge=0, le=BASELINE_DAYS)
|
||||
timed_days: int = Field(ge=0, le=BASELINE_DAYS)
|
||||
exists: bool
|
||||
|
||||
|
||||
class SweepState(BaseModel):
|
||||
|
|
@ -187,20 +184,14 @@ def _spend_spike(window: ResourceWindow) -> tuple[float, float] | None:
|
|||
return (window.spend, baseline) if triggered else None
|
||||
|
||||
|
||||
def _traffic_change(window: ResourceWindow) -> tuple[float, float] | None:
|
||||
def _traffic_spike(window: ResourceWindow) -> tuple[float, float] | None:
|
||||
baseline: Final = window.base_requests / BASELINE_DAYS
|
||||
spike: Final = (
|
||||
window.active_days >= MIN_ACTIVE_DAYS
|
||||
and window.requests >= TRAFFIC_SPIKE_MULTIPLIER * baseline
|
||||
and window.requests - baseline >= TRAFFIC_SPIKE_MIN_INCREASE
|
||||
)
|
||||
drop: Final = (
|
||||
window.exists
|
||||
and window.active_days == BASELINE_DAYS
|
||||
and baseline >= TRAFFIC_DROP_MIN_BASELINE
|
||||
and window.requests < TRAFFIC_DROP_RATIO * baseline
|
||||
)
|
||||
return (window.requests, baseline) if spike or drop else None
|
||||
return (window.requests, baseline) if spike else None
|
||||
|
||||
|
||||
def _slower_responses(window: ResourceWindow) -> tuple[float, float] | None:
|
||||
|
|
@ -231,7 +222,7 @@ def _more_failures(window: ResourceWindow) -> tuple[float, float] | None:
|
|||
def detect(scope: PerformanceScope, window: ResourceWindow, day: date) -> tuple[AlertDetection, ...]:
|
||||
checks: Final[tuple[tuple[AlertType, tuple[float, float] | None, int], ...]] = (
|
||||
("spend", _spend_spike(window), window.requests),
|
||||
("traffic", _traffic_change(window), window.requests),
|
||||
("traffic", _traffic_spike(window), window.requests),
|
||||
("latency", _slower_responses(window), window.timed),
|
||||
("reliability", _more_failures(window), window.requests),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -80,33 +80,18 @@ class _Source:
|
|||
resource_id: LiteralString
|
||||
requests: LiteralString
|
||||
filter: LiteralString
|
||||
exists: LiteralString
|
||||
|
||||
|
||||
_SOURCES: Final[Mapping[PerformanceScope, _Source]] = {
|
||||
"gateway": _Source('"LiteLLM_DailyModelUsage"', "'gateway'", "request_count", "", "true"),
|
||||
"model": _Source('"LiteLLM_DailyModelUsage"', "model_group", "request_count", "", "true"),
|
||||
"team": _Source(
|
||||
'"LiteLLM_DailyTeamSpend"',
|
||||
"team_id",
|
||||
"api_requests",
|
||||
"",
|
||||
'EXISTS (SELECT 1 FROM "LiteLLM_TeamTable" t WHERE t.team_id = page.resource_id AND NOT t.blocked)',
|
||||
),
|
||||
"user": _Source(
|
||||
'"LiteLLM_DailyUserSpend"',
|
||||
"user_id",
|
||||
"api_requests",
|
||||
"",
|
||||
'EXISTS (SELECT 1 FROM "LiteLLM_UserTable" u WHERE u.user_id = page.resource_id)',
|
||||
),
|
||||
"gateway": _Source('"LiteLLM_DailyModelUsage"', "'gateway'", "request_count", ""),
|
||||
"model": _Source('"LiteLLM_DailyModelUsage"', "model_group", "request_count", ""),
|
||||
"team": _Source('"LiteLLM_DailyTeamSpend"', "team_id", "api_requests", ""),
|
||||
"user": _Source('"LiteLLM_DailyUserSpend"', "user_id", "api_requests", ""),
|
||||
"key": _Source(
|
||||
'"LiteLLM_DailyUserSpend"',
|
||||
"api_key",
|
||||
"api_requests",
|
||||
" AND api_key ~ '^[0-9a-f]{64}$'",
|
||||
'EXISTS (SELECT 1 FROM "LiteLLM_VerificationToken" k WHERE k.token = page.resource_id'
|
||||
" AND k.blocked IS NOT TRUE AND (k.expires IS NULL OR k.expires > now()))",
|
||||
),
|
||||
}
|
||||
|
||||
|
|
@ -127,8 +112,7 @@ def _page_sql(scope: PerformanceScope, wrapped: bool) -> LiteralString:
|
|||
if scope == "gateway"
|
||||
else f" GROUP BY {source.resource_id} ORDER BY {source.resource_id}"
|
||||
)
|
||||
return f"""WITH page AS (
|
||||
SELECT {source.resource_id} AS resource_id,
|
||||
return f"""SELECT {source.resource_id} AS resource_id,
|
||||
COALESCE(SUM(spend) FILTER (WHERE date = $1), 0)::float8 AS spend,
|
||||
COALESCE(SUM(spend) FILTER (WHERE date < $1), 0)::float8 AS base_spend,
|
||||
COALESCE(SUM({source.requests}) FILTER (WHERE date = $1), 0)::bigint AS requests,
|
||||
|
|
@ -143,9 +127,7 @@ def _page_sql(scope: PerformanceScope, wrapped: bool) -> LiteralString:
|
|||
COUNT(DISTINCT date) FILTER (WHERE date < $1 AND timed_requests > 0) AS timed_days
|
||||
FROM {source.table}
|
||||
WHERE date BETWEEN $2 AND $1{where}{group}
|
||||
LIMIT $3::int
|
||||
)
|
||||
SELECT page.*, {source.exists} AS exists FROM page ORDER BY resource_id"""
|
||||
LIMIT $3::int"""
|
||||
|
||||
|
||||
def _next_id_sql(scope: PerformanceScope, wrapped: bool) -> LiteralString:
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ async def test_a_full_sweep_saves_one_alert_per_real_change_and_nothing_for_norm
|
|||
write_rows('INSERT INTO "LiteLLM_UserTable" (user_id) VALUES (%s)', (f"{p}-user-stopped",))
|
||||
_seed("user", f"{p}-user-stopped", STEADY, None)
|
||||
_seed("user", f"{p}-user-deleted", STEADY, None)
|
||||
_seed("user", f"{p}-user-busy", STEADY, Day(requests=20_000, timed=20_000, response_ms=2_000_000))
|
||||
_seed("key", fixture.key("slow"), STEADY, Day(response_ms=1_000_000))
|
||||
_seed("model", f"{p}-model", STEADY, Day(failed=100))
|
||||
|
||||
|
|
@ -170,7 +171,7 @@ async def test_a_full_sweep_saves_one_alert_per_real_change_and_nothing_for_norm
|
|||
assert int(str(age["seconds"])) < 300
|
||||
assert fixture.saved() == {
|
||||
(f"{p}-team-spike", "spend"): ("team", "open"),
|
||||
(f"{p}-user-stopped", "traffic"): ("user", "open"),
|
||||
(f"{p}-user-busy", "traffic"): ("user", "open"),
|
||||
(fixture.key("slow"), "latency"): ("key", "open"),
|
||||
(f"{p}-model", "reliability"): ("model", "open"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import pytest
|
|||
|
||||
from litellm.models.alert import AlertDetection, MetricEvidence
|
||||
from litellm.models.performance_alert import (
|
||||
SCOPES,
|
||||
PerformanceScope,
|
||||
ResourceWindow,
|
||||
SweepState,
|
||||
advance,
|
||||
|
|
@ -29,7 +31,6 @@ STEADY: Final = {
|
|||
"base_timed": 7000,
|
||||
"active_days": 7,
|
||||
"timed_days": 7,
|
||||
"exists": True,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -45,6 +46,19 @@ def test_steady_usage_raises_nothing() -> None:
|
|||
assert _types() == ()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("scope", SCOPES)
|
||||
@pytest.mark.parametrize("requests", (0, 100))
|
||||
def test_quiet_or_idle_resources_do_not_raise_traffic_alerts(scope: PerformanceScope, requests: int) -> None:
|
||||
window: Final = _window(
|
||||
resource_id="a" * 64 if scope == "key" else "resource-a",
|
||||
requests=requests,
|
||||
failed=0,
|
||||
response_ms=requests * 100,
|
||||
timed=requests,
|
||||
)
|
||||
assert detect(scope, window, DAY) == ()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("changes", "expected"),
|
||||
(
|
||||
|
|
@ -57,11 +71,6 @@ def test_steady_usage_raises_nothing() -> None:
|
|||
({"requests": 1100, "failed": 0, "response_ms": 110_000, "timed": 1100, "base_requests": 700}, ("traffic",)),
|
||||
({"requests": 1099, "failed": 0, "response_ms": 109_900, "timed": 1099, "base_requests": 700}, ()),
|
||||
({"requests": 50_000, "failed": 0, "active_days": 3}, ()),
|
||||
({"requests": 99, "failed": 0, "timed": 99, "response_ms": 9900, "base_requests": 3500}, ("traffic",)),
|
||||
({"requests": 100, "failed": 0, "timed": 100, "response_ms": 10_000, "base_requests": 3500}, ()),
|
||||
({"requests": 0, "failed": 0, "timed": 0, "response_ms": 0, "base_requests": 3500, "active_days": 6}, ()),
|
||||
({"requests": 0, "failed": 0, "timed": 0, "response_ms": 0, "base_requests": 3500, "exists": False}, ()),
|
||||
({"requests": 0, "failed": 0, "timed": 0, "response_ms": 0, "base_requests": 3493}, ()),
|
||||
({"response_ms": 600_000}, ("latency",)),
|
||||
({"response_ms": 599_000}, ()),
|
||||
({"response_ms": 60_000_000, "timed": 99}, ()),
|
||||
|
|
|
|||
|
|
@ -112,7 +112,6 @@ def spend_window() -> Mapping[str, object]:
|
|||
"base_timed": 0,
|
||||
"active_days": 7,
|
||||
"timed_days": 0,
|
||||
"exists": True,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue