mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-29 06:33:28 +00:00
fix(proxy): seed the applied reload revision at startup
A pod adopted whatever revision it found on its first poll, so a manual reload published while the pod was starting was marked applied without ever being served and the pod kept the prices it fetched at import. Read the row once at startup instead, right after that fetch, and treat a missing row as revision 0
This commit is contained in:
parent
e79109c7e9
commit
9839b95bc8
4 changed files with 412 additions and 948 deletions
|
|
@ -137,10 +137,11 @@ def pod_reload_is_due(
|
|||
) -> bool:
|
||||
"""
|
||||
Whether this pod should reload now. A revision it has not applied means a manual reload
|
||||
it has not served; ``pod_applied_revision`` is None only until the pod's first poll, when
|
||||
its data is boot-fresh and it simply adopts whatever revision it finds. Interval reloads
|
||||
compare against this pod's own data, and a schedule that has never run anywhere fires
|
||||
immediately rather than one interval later
|
||||
it has not served; ``pod_applied_revision`` is normally seeded at startup, and is None
|
||||
only if that read failed, in which case the pod adopts rather than re-serving a request
|
||||
its boot-time data may already satisfy. Interval reloads compare against this pod's own
|
||||
data, and a schedule that has never run anywhere fires immediately rather than one
|
||||
interval later
|
||||
"""
|
||||
if pod_applied_revision is not None and schedule.reload_revision != pod_applied_revision:
|
||||
verbose_proxy_logger.info("%s reload triggered by manual reload request", description)
|
||||
|
|
|
|||
|
|
@ -3863,8 +3863,9 @@ class ProxyConfig:
|
|||
)
|
||||
|
||||
self.model_cost_map_loaded_at: datetime = get_model_cost_map_loaded_at() or utc_now()
|
||||
# None until the first poll adopts whatever revision the row carries; this pod's
|
||||
# data is boot-fresh, so a request published before it started is already satisfied
|
||||
# Seeded from the row at startup, as close as possible to the boot-time fetch above,
|
||||
# so a request published while this pod was starting is not mistaken for one its own
|
||||
# data already satisfies. None only if that read never happened or failed
|
||||
self.model_cost_map_applied_revision: int | None = None
|
||||
|
||||
def is_yaml(self, config_file_path: str) -> bool:
|
||||
|
|
@ -6439,6 +6440,21 @@ class ProxyConfig:
|
|||
if self._should_load_db_object(object_type="model_cost_map"):
|
||||
await self._check_and_reload_model_cost_map(prisma_client=prisma_client)
|
||||
|
||||
async def seed_model_cost_map_revision(self, prisma_client: PrismaClient) -> None:
|
||||
"""
|
||||
Adopt the currently published revision once at startup, before the periodic job runs.
|
||||
|
||||
Without this the first poll adopts whatever it finds, so a manual reload published
|
||||
while this pod was starting would be marked applied without ever being served, and
|
||||
the pod would keep the prices it fetched at import. A missing row means nobody has
|
||||
ever requested a reload, which is revision 0.
|
||||
"""
|
||||
try:
|
||||
schedule = await read_reload_schedule(prisma_client, MODEL_COST_MAP_RELOAD_PARAM_NAME)
|
||||
self.model_cost_map_applied_revision = schedule.reload_revision if schedule is not None else 0
|
||||
except Exception as e:
|
||||
verbose_proxy_logger.exception(f"Error seeding model cost map reload revision: {str(e)}")
|
||||
|
||||
async def _check_and_reload_model_cost_map(self, prisma_client: PrismaClient):
|
||||
"""
|
||||
Check if model cost map needs to be reloaded based on database configuration.
|
||||
|
|
@ -8038,6 +8054,7 @@ class ProxyStartupEvent:
|
|||
config_reload_interval_seconds = 30
|
||||
|
||||
### PERIODIC RELOADS (model cost map, anthropic beta headers) ###
|
||||
await proxy_config.seed_model_cost_map_revision(prisma_client)
|
||||
scheduler.add_job(
|
||||
proxy_config.check_periodic_reloads,
|
||||
"interval",
|
||||
|
|
|
|||
|
|
@ -150,9 +150,9 @@ def test_manual_request_is_identified_not_ordered():
|
|||
assert (unapplied, applied) == (True, False)
|
||||
|
||||
|
||||
def test_fresh_pod_adopts_the_revision_without_reloading():
|
||||
"""A pod that just booted holds data newer than any earlier request, so its first poll
|
||||
must not re-serve one; the interval is the only thing that can make it due"""
|
||||
def test_pod_without_a_seeded_revision_adopts_without_reloading():
|
||||
"""Fallback when the startup seed failed: the pod cannot tell whether its boot-time data
|
||||
already satisfies the request, and re-serving one every restart is the worse guess"""
|
||||
assert (
|
||||
pod_reload_is_due(
|
||||
schedule=ReloadSchedule(reload_revision=12),
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue