perf(spend): move cost-callback payload deepcopy off the request event loop - #31579
Conversation
|
|
Greptile SummaryThis PR moves spend-tracking payload copying out of the awaited request path. The main changes are:
Confidence Score: 5/5The change is narrowly scoped to spend-update copy timing and preserves the intended background isolation behavior. The modified code path is covered by targeted regression tests that check no request-path deepcopy occurs and that daily helper payload isolation is retained. No specific files need additional attention.
What T-Rex did
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Proof of fix (live proxy)Ran this branch as a live proxy against real Postgres and the real OpenAI API (openai/gpt-4o-mini, real spend). The change removes all three copy.deepcopy calls from the awaited request path and takes the one copy the daily-spend helpers need inside the already-backgrounded _batch_database_updates. The proof that matters is parity: the spend log and the daily-spend tables must still be written with correct, intact, isolated payloads Confirmed the running proxy loads this branch (no deepcopy on the request path, one inside the background task) One real request, then the persisted spend log and daily-spend rows The spend log row carries the full metadata payload and the daily user/tag aggregates advanced, so moving the copy off the request path did not drop or corrupt any of the backgrounded writes |
|
On the "daily spend helper isolation" note: the flagged window requires
The T-Rex harness surfaced the window by injecting a mutation after return, which is a code path the production callers do not exercise. The new regression test plus the existing Keeping a synchronous snapshot on the awaited path is exactly the |
|
That's a thorough and convincing walkthrough of the call graph. You're right on all three counts:
The new Fair point — withdrawing the concern. |
e686fcc to
8b82e7d
Compare
8b82e7d to
829e698
Compare
Relevant issues
Linear ticket
Resolves LIT-4088
Pre-Submission checklist
@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewScreenshots / Proof of Fix
Live-proxy spend-tracking parity verification to follow in a comment
Type
🚄 Infrastructure
Changes
_PROXY_track_cost_callbackpersists spend by awaitingDBSpendUpdateWriter.update_database, which ran three synchronouscopy.deepcopycalls on the request event loop before deferring the table updates to a background task.copy.deepcopyis pure-Python and GIL-bound, so each copy blocked the loop; under load this was part of the multi-secondupdate_databasea customer measuredEvery consumer of the payload is read-only: the daily-spend helpers construct new dicts,
_update_tag_dbparsesrequest_tagsread-only, and_insert_spend_log_to_dbonly takes a lock and appends the reference to the in-memory queue that is later serialized read-only. So the spend-log insert now receives the payload directly with no copy, and the single deepcopy the daily helpers need is taken at the top of_batch_database_updates, which already runs inside the backgroundasyncio.create_task. The awaited request path now performs no deepcopyA regression test counts
copy.deepcopycalls and asserts none occur beforeupdate_databasereturns, that the relocated copy still isolates the daily helpers from later mutation of the source payload, and the existing daily-agent isolation test is preserved