fix(prometheus): give each proxy boot its own auto-created PROMETHEUS_MULTIPROC_DIR

This commit is contained in:
xuan 2026-10-12 13:45:04 +08:00
parent 102619d47a
commit 48b95aa0c7
2 changed files with 56 additions and 5 deletions

View file

@ -724,12 +724,16 @@ class ProxyInitializationHelpers:
wipe_directory(configured_dir)
return None
multiproc_dir: Final = configured_dir or os.path.join(tempfile.gettempdir(), "litellm_prometheus_multiproc")
os.environ["PROMETHEUS_MULTIPROC_DIR"] = multiproc_dir
if configured_dir:
# An operator-set directory is theirs to manage; keep the historical wipe-on-boot.
os.makedirs(configured_dir, exist_ok=True)
wipe_directory(configured_dir)
multiproc_dir, action = configured_dir, "Using existing"
else:
# Unique per boot: a fixed shared name lets a second proxy on this host wipe the first one's counters.
multiproc_dir, action = tempfile.mkdtemp(prefix="litellm_prometheus_multiproc_"), "Auto-created"
os.makedirs(multiproc_dir, exist_ok=True)
wipe_directory(multiproc_dir)
action: Final = "Using existing" if configured_dir else "Auto-created"
os.environ["PROMETHEUS_MULTIPROC_DIR"] = multiproc_dir
print(f"LiteLLM: {action} PROMETHEUS_MULTIPROC_DIR={multiproc_dir}")
return multiproc_dir

View file

@ -6,8 +6,10 @@ ProxyInitializationHelpers._maybe_setup_prometheus_multiproc_dir.
from __future__ import annotations
import os
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path
from typing import Final
from unittest.mock import patch
@ -193,6 +195,8 @@ class TestMaybeSetupPrometheusMultiprocDir:
result_dir = os.environ.get("PROMETHEUS_MULTIPROC_DIR")
assert result_dir is not None
assert os.path.isdir(result_dir)
legacy_shared = os.path.join(tempfile.gettempdir(), "litellm_prometheus_multiproc")
assert result_dir != legacy_shared
# Cleanup
os.environ.pop("PROMETHEUS_MULTIPROC_DIR", None)
@ -257,3 +261,46 @@ class TestMaybeSetupPrometheusMultiprocDir:
assert os.environ["PROMETHEUS_MULTIPROC_DIR"] == str(tmp_path)
assert not admitted.exists()
assert not samples.exists()
def test_auto_created_dir_is_unique_per_boot_and_keeps_sibling_counters(self):
"""A fixed default dir made the second proxy boot wipe the first proxy's live counters (issue #42566)."""
with patch.dict(os.environ, {}, clear=False):
os.environ.pop("PROMETHEUS_MULTIPROC_DIR", None)
os.environ.pop("prometheus_multiproc_dir", None)
litellm_settings = {"callbacks": ["prometheus"]}
first = ProxyInitializationHelpers._maybe_setup_prometheus_multiproc_dir(
num_workers=4, litellm_settings=litellm_settings
)
assert first is not None and os.path.isdir(first)
stale = os.path.join(first, "counter_proxy_one.db")
with open(stale, "w") as f:
f.write("live")
os.environ.pop("PROMETHEUS_MULTIPROC_DIR", None) # simulate a second, independent boot
second = ProxyInitializationHelpers._maybe_setup_prometheus_multiproc_dir(
num_workers=4, litellm_settings=litellm_settings
)
assert second is not None and os.path.isdir(second)
assert first != second
assert os.path.exists(stale)
os.environ.pop("PROMETHEUS_MULTIPROC_DIR", None)
shutil.rmtree(first, ignore_errors=True)
shutil.rmtree(second, ignore_errors=True)
def test_configured_dir_is_still_wiped_on_boot(self, tmp_path):
"""A directory the operator set keeps its historical wipe-on-boot lifecycle."""
stale = tmp_path / "counter_stale.db"
stale.write_text("old")
with patch.dict(os.environ, {"PROMETHEUS_MULTIPROC_DIR": str(tmp_path)}):
result_dir = ProxyInitializationHelpers._maybe_setup_prometheus_multiproc_dir(
num_workers=4,
litellm_settings={"callbacks": ["prometheus"]},
)
assert result_dir == str(tmp_path)
assert not stale.exists()