This commit is contained in:
Ali Abbas 2026-08-28 09:09:45 +10:00 committed by GitHub
commit 6485193f98
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 85 additions and 1 deletions

View file

@ -1645,6 +1645,8 @@ LITELLM_SETTINGS_SAFE_DB_OVERRIDES: Final = [
"cost_margin_config",
"block_requests_for_models_without_pricing",
"budget_exceeded_throttle_percentage",
# Proxy-wide budget stored via POST /config/update; applied to litellm.max_budget on reload.
"max_budget",
# Every field editable from the Admin UI (proxy_server._GENERAL_SETTINGS_UI_LITELLM_FIELDS)
# must be listed here so a DB write from one worker overrides the live litellm attribute on
# the others when config reloads; otherwise peer workers stay on their startup value.

View file

@ -3835,6 +3835,27 @@ def _scrub_guardrail_inner(inner: dict[str, JsonValue]) -> None:
inner["guardrail"] = None
def _apply_safe_db_litellm_setting(key: str, value: object) -> None:
"""Apply a DB-overlaid ``litellm_settings`` key to the live ``litellm`` module.
``max_budget`` is coerced to float to match startup config loading
(``ProxyConfig.load_config``). A ``None`` DB value leaves the current
runtime attribute unchanged; a non-numeric value is ignored (with a
warning) rather than aborting the reload of an already-running proxy.
"""
if key == "max_budget":
if value is None:
return
try:
budget = float(value)
except (TypeError, ValueError):
verbose_proxy_logger.warning("Ignoring non-numeric DB litellm_settings.max_budget override: %r", value)
return
litellm.max_budget = budget
return
setattr(litellm, key, value)
def _scrub_db_overlay_remote_module_loads(section: str, db_value: JsonValue) -> JsonValue:
"""Strip ``s3://`` / ``gcs://`` entries from the DB-overlay value for
fields whose contents reach ``get_instance_fn``. The same scheme is
@ -6656,7 +6677,7 @@ class ProxyConfig:
elif param_name == "litellm_settings" and isinstance(db_param_value, dict):
for key, value in db_param_value.items():
if key in LITELLM_SETTINGS_SAFE_DB_OVERRIDES: # params that are safe to override with db values
setattr(litellm, key, value)
_apply_safe_db_litellm_setting(key, value)
# If param doesn't exist in config, add it
if param_name not in current_config:

View file

@ -9838,6 +9838,67 @@ def test_prompt_caching_settings_propagate_on_config_reload(monkeypatch, field_n
assert getattr(litellm, field_name) == db_value
@pytest.mark.parametrize(
"db_value, expected",
[
(10, 10.0),
("10", 10.0),
(0.5, 0.5),
],
)
def test_max_budget_propagates_on_config_reload(monkeypatch, db_value, expected):
"""Regression for #36533: a DB-stored litellm_settings.max_budget must overlay the live
litellm.max_budget when config reloads (STORE_MODEL_IN_DB=True). It was absent from
LITELLM_SETTINGS_SAFE_DB_OVERRIDES, so peer workers kept enforcing the stale config.yaml value."""
import litellm.proxy.proxy_server as ps
# peer worker booted with the stale config.yaml value
monkeypatch.setattr(litellm, "max_budget", 0.00001)
pc = ps.ProxyConfig()
pc._update_config_fields(
current_config={"litellm_settings": {}},
param_name="litellm_settings",
db_param_value={"max_budget": db_value},
)
assert litellm.max_budget == expected
assert isinstance(litellm.max_budget, float)
def test_max_budget_none_db_value_leaves_runtime_unchanged(monkeypatch):
"""A null DB max_budget must not clobber the running litellm.max_budget."""
import litellm.proxy.proxy_server as ps
monkeypatch.setattr(litellm, "max_budget", 7.5)
pc = ps.ProxyConfig()
pc._update_config_fields(
current_config={"litellm_settings": {}},
param_name="litellm_settings",
db_param_value={"max_budget": None},
)
assert litellm.max_budget == 7.5
def test_max_budget_invalid_db_value_is_ignored(monkeypatch):
"""A non-numeric DB max_budget must be skipped (logged), not abort the reload of a
running proxy or clobber the live litellm.max_budget."""
import litellm.proxy.proxy_server as ps
monkeypatch.setattr(litellm, "max_budget", 7.5)
pc = ps.ProxyConfig()
pc._update_config_fields(
current_config={"litellm_settings": {}},
param_name="litellm_settings",
db_param_value={"max_budget": "not-a-number"},
)
assert litellm.max_budget == 7.5
def test_get_config_list_marks_untouched_prompt_caching_flag_as_not_set(monkeypatch):
"""The flag defaults to False rather than None, so a plain 'is not None' check would
report the default as 'In Config' and imply an admin had set it."""