mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
* fix(accounting): stop delivery metrics from scanning retained receipts on every flush The backlog query now reads only pending and parked deliveries, so its cost follows the backlog instead of retained receipt history. Batch count and table size are measured once per check interval per pod, and the storage and delayed-delivery alerts repeat at most once per interval instead of every flush Fixes #50475 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(accounting): prove the storage query reruns only when its interval is due Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(accounting): read the check interval on each flush so YAML environment_variables apply The writer is built at proxy import, before the config's environment_variables load, so reading the interval there ignored values set in config.yaml Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(router): wait for router accounting instead of sleeping in user-config limit tests Each request ended with a 0.3s sleep and hoped the router's usage writes had landed, so under CI load a concurrent request could read counters mid-update. The tests now flush the logging worker and wait for every task the requests scheduled, and a retired router's counter flush lands before the next router reads Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Joshua Valluru <326636767+joshua-berri@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
62 lines
2.2 KiB
Python
62 lines
2.2 KiB
Python
import importlib.util
|
|
import sys
|
|
|
|
import pytest
|
|
from prometheus_client.metrics import MetricWrapperBase
|
|
|
|
from litellm.accounting import metrics
|
|
from litellm.accounting.metrics import Cadence, record_backlog, record_storage
|
|
from litellm.repositories.accounting_delivery_repository import DeliveryBacklog, DeliveryStorage
|
|
|
|
_BACKLOG = DeliveryBacklog(pending_count=4, parked_count=1, oldest_pending_seconds=-3.0)
|
|
_STORAGE = DeliveryStorage(batch_count=7, table_bytes=8192)
|
|
|
|
|
|
def _sample(metric: MetricWrapperBase, suffix: str = "") -> float:
|
|
family = metric.collect()[0]
|
|
return next(sample.value for sample in family.samples if sample.name == family.name + suffix)
|
|
|
|
|
|
def test_delivery_metrics_publish_backlog_and_clamp_clock_skew() -> None:
|
|
instruments = metrics._INSTRUMENTS
|
|
assert instruments is not None
|
|
batches_before = _sample(instruments.batch_time, "_count")
|
|
|
|
record_backlog(_BACKLOG, 0.5)
|
|
record_storage(_STORAGE)
|
|
|
|
assert (
|
|
_sample(instruments.pending),
|
|
_sample(instruments.parked),
|
|
_sample(instruments.oldest),
|
|
_sample(instruments.batch_count),
|
|
_sample(instruments.table_bytes),
|
|
) == (4.0, 1.0, 0.0, 7.0, 8192.0)
|
|
assert _sample(instruments.batch_time, "_count") == batches_before + 1
|
|
|
|
|
|
def test_delivery_metrics_are_skipped_when_prometheus_client_is_not_installed(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
monkeypatch.setitem(sys.modules, "prometheus_client", None)
|
|
spec = importlib.util.spec_from_file_location("accounting_metrics_without_prometheus", metrics.__file__)
|
|
assert spec is not None and spec.loader is not None
|
|
module = importlib.util.module_from_spec(spec)
|
|
monkeypatch.setitem(sys.modules, spec.name, module)
|
|
|
|
spec.loader.exec_module(module)
|
|
|
|
assert module.record_backlog(_BACKLOG, 0.5) is None
|
|
assert module.record_storage(_STORAGE) is None
|
|
|
|
|
|
def test_cadence_is_due_once_per_interval() -> None:
|
|
now = [100.0]
|
|
cadence = Cadence(lambda: now[0])
|
|
|
|
observed = []
|
|
for moment in (100.0, 101.0, 999.9, 1000.0, 1000.0, 1899.0, 1900.0):
|
|
now[0] = moment
|
|
observed.append(cadence.due(900))
|
|
|
|
assert observed == [True, False, False, True, False, False, True]
|