mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-13 23:11:40 +00:00
fix: persist budget_id to DB for auto-created end users using max_end_user_budget_id
When `max_end_user_budget_id` is configured, end users created via the `x-litellm-end-user-id` header have their default budget applied only in-memory at auth time. The `budget_id` is never written to the `LiteLLM_EndUserTable` row, so the budget reset job (which queries `WHERE budget_id IN (...)`) never finds these users — their spend accumulates forever and never resets. This commit: 1. Includes `budget_id` in the upsert create clause in `update_end_user_spend()` when the default budget is configured, so newly created end users get `budget_id` persisted from the start. 2. Adds a lazy backfill in `_apply_default_budget_to_end_user()` that writes `budget_id` to the DB for existing users where it is NULL, so pre-existing users self-heal on their next request. 3. Adds the `budget_id` field to the `LiteLLM_EndUserTable` Pydantic model to match the Prisma schema. Fixes #25386
This commit is contained in:
parent
072d4108c3
commit
8604d4518d
3 changed files with 29 additions and 8 deletions
|
|
@ -2897,6 +2897,7 @@ class LiteLLM_EndUserTable(LiteLLMPydanticObjectBase):
|
|||
spend: float = 0.0
|
||||
allowed_model_region: Optional[AllowedModelRegion] = None
|
||||
default_model: Optional[str] = None
|
||||
budget_id: Optional[str] = None
|
||||
litellm_budget_table: Optional[LiteLLM_BudgetTable] = None
|
||||
object_permission_id: Optional[str] = None
|
||||
object_permission: Optional[LiteLLM_ObjectPermissionTable] = None
|
||||
|
|
|
|||
|
|
@ -918,9 +918,26 @@ async def _apply_default_budget_to_end_user(
|
|||
if default_budget is not None:
|
||||
# Apply default budget to end user object
|
||||
end_user_obj.litellm_budget_table = default_budget
|
||||
verbose_proxy_logger.debug(
|
||||
f"Applied default budget {litellm.max_end_user_budget_id} to end user {end_user_obj.user_id}"
|
||||
)
|
||||
|
||||
# Backfill budget_id to DB for existing users that were created without it
|
||||
if end_user_obj.budget_id is None:
|
||||
try:
|
||||
await prisma_client.db.litellm_endusertable.update(
|
||||
where={"user_id": end_user_obj.user_id},
|
||||
data={"budget_id": litellm.max_end_user_budget_id},
|
||||
)
|
||||
end_user_obj.budget_id = litellm.max_end_user_budget_id
|
||||
verbose_proxy_logger.debug(
|
||||
f"Persisted default budget_id {litellm.max_end_user_budget_id} to end user {end_user_obj.user_id}"
|
||||
)
|
||||
except Exception:
|
||||
verbose_proxy_logger.debug(
|
||||
f"Failed to persist default budget_id for end user {end_user_obj.user_id}"
|
||||
)
|
||||
else:
|
||||
verbose_proxy_logger.debug(
|
||||
f"Applied default budget {litellm.max_end_user_budget_id} to end user {end_user_obj.user_id}"
|
||||
)
|
||||
|
||||
return end_user_obj
|
||||
|
||||
|
|
|
|||
|
|
@ -4679,14 +4679,17 @@ class ProxyUpdateSpend:
|
|||
) in end_user_list_transactions.items():
|
||||
if litellm.max_end_user_budget is not None:
|
||||
pass
|
||||
_create_data: dict = {
|
||||
"user_id": end_user_id,
|
||||
"spend": response_cost,
|
||||
"blocked": False,
|
||||
}
|
||||
if litellm.max_end_user_budget_id is not None:
|
||||
_create_data["budget_id"] = litellm.max_end_user_budget_id
|
||||
batcher.litellm_endusertable.upsert(
|
||||
where={"user_id": end_user_id},
|
||||
data={
|
||||
"create": {
|
||||
"user_id": end_user_id,
|
||||
"spend": response_cost,
|
||||
"blocked": False,
|
||||
},
|
||||
"create": _create_data,
|
||||
"update": {"spend": {"increment": response_cost}},
|
||||
},
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue