litellm/litellm-proxy-extras/litellm_proxy_extras
devin-ai-integration[bot] 4e2dd65549
fix(interactions): keep background interaction bills through crashes, late restarts, and deployment keys (#45743)
* fix(interactions): keep background interaction bills through crashes, late restarts, and deployment keys

A settlement claim is now a lease, so a row whose settler died between claim and
outcome is claimable again after the lease and boot resumes it. A resumed poll
gets the full poll window and fetches with the serving deployment's credentials
from the live router. The stored create context keeps the request tags and the
request metadata that the creating worker's own spend row used

* fix(interactions): bill a lapsed claim's takeover only when no spend row exists

A settler that billed and then died, or failed to record the outcome, left the row unsettled, so the replica that took over its lapsed claim billed the interaction a second time. A takeover now looks up the spend row keyed by the interaction id and records the row as billed when it finds one.

* fix(interactions): settle Vertex AI and edited deployments, never double bill with spend logs off

A takeover with spend logs off records the interaction unsettled instead of
billing it again, and a release records its outcome before freeing the budget
reservation. A resumed or live fetch carries the deployment's Vertex AI project,
location, and credentials, and a stale deployment id falls back to the model
group only when one same-provider deployment serves it. A poll stops at the
first 400, 401, 403, or 404, string request tags no longer fail the create,
and settled_at gets an index built concurrently.

* fix(interactions): leave a live replica's interaction to it when a resumed poll cannot read it

A replica that boots with credentials unable to read an interaction got a 404 on its resumed poll and settled the row as unsettled at once, so the replica that created it, still polling, found it settled and never billed it. A resumed poll that gets a 400, 401, 403, or 404 now stops fetching and keeps checking the row until its poll window ends, and settles it as unsettled only when no other replica did.

* fix(interactions): keep the creator's metadata on a resumed bill and retry outcome writes inside the claim lease

A bill another replica writes now carries the metadata the creating worker's own
spend row is built from, so a client's metadata.model_group no longer relabels it.
A failed outcome write is retried for half the claim lease before the budget
reservation is left to a takeover, and the creating replica retries every fetch
error for its whole window again, as main does. The resume integration case now
checks that a resumed fetch uses the deployment's own key.

* fix(interactions): resume background interaction polls only after database models load

Boot resume ran before the proxy loaded the models stored in the database,
so a resumed poll for a model added through /model/new or the Admin UI
fetched with env credentials. A 4xx there stops a resumed poll, so the bill
was lost. The settlement now installs after the database models load.

The integration test resumes a database model with an eager first fetch
and fails with the old startup order.

* fix(interactions): renew a settling claim so a slow settle is never taken over and billed twice

A settle runs every success callback in turn, and one slow callback could
hold it past the 5 minute claim lease. A booting replica or a DELETE then
took the live claim over, found no spend row yet, and billed the
interaction a second time. The settler now renews its claim every third
of the lease until it records the outcome, so only a settler that stopped
renewing is taken over.

A takeover also read the spend log after writing its claim, so a failed
read left the row under the taker's own fresh claim, which its poll then
took for another settler's and left unbilled until a reboot. The spend
row is now read before the claim is written, so a failed read takes
nothing and the claim is retried on the next poll.

* test(spend): cover lapsed claim takeovers, rotated deployment keys, late restarts, and resumed bill tags

---------

Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
2026-10-16 12:00:08 +00:00
..
migrations fix(interactions): keep background interaction bills through crashes, late restarts, and deployment keys (#45743) 2026-10-16 12:00:08 +00:00
__init__.py install prisma migration files - connects litellm proxy to litellm's prisma migration files (#9637) 2025-03-29 15:27:09 -07:00
_logging.py fix(proxy): honor LITELLM_LOG for uvicorn and proxy extras loggers 2026-09-15 21:55:37 +00:00
_redaction.py fix(proxy-extras): accept unencoded DB passwords in the v2 migration lock and redact its errors (#46592) 2026-10-15 14:47:23 -07:00
migration_lock.py fix(proxy-extras): hold only Prisma's lock key during migrate deploy so it never waits on the request log index build (#46660) 2026-10-15 14:47:33 -07:00
migration_recovery.py fix(proxy-extras): build the SpendLogs indexes in the migration job instead of in migrations (#43948) 2026-10-01 14:12:22 -07:00
prisma_toolchain.py fix(proxy-extras): bound migration lock waits with SET LOCAL lock_timeout in the migration SQL (#46329) 2026-10-13 20:51:03 -07:00
py.typed fix(lint): bring basedpyright rule counts back under their budget limits 2026-08-05 10:23:02 -07:00
replica_identity.py fix(proxy-extras): kill the whole Prisma process group when a command times out 2026-09-02 18:29:55 -07:00
request_log_indexes.py fix(proxy-extras): bound the lock waits of the partitioned SpendLogs index build (#44109) 2026-10-01 18:28:50 -07:00
schema.prisma fix(interactions): keep background interaction bills through crashes, late restarts, and deployment keys (#45743) 2026-10-16 12:00:08 +00:00
utils.py fix(proxy-extras): accept unencoded DB passwords in the v2 migration lock and redact its errors (#46592) 2026-10-15 14:47:23 -07:00