fix(billing): 防止 snapshot 在 api_key/upstream 被删后写入失败#168
Merged
Conversation
snapshot 写入时若 caller 传入的 api_key_id / upstream_id 在 api_keys / upstreams 中已不存在(典型场景:冒烟测试或外部清理在 SSE 响应结束后立刻 删除临时资源),INSERT 会撞 FK 约束。 修复方式:在 calculateAndPersistRequestBillingSnapshot 入口处从 request_logs 反查 apiKeyId / upstreamId 作为 snapshot 的最终值。 request_logs 行已被 DB 的 ON DELETE SET NULL 处理过,天然 FK 安全。 所有 8 处调用点自动受益,无需改动调用方。 补充两个单元测试覆盖 race 与 request_logs 缺失兜底两种分支。
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #168 +/- ##
==========================================
+ Coverage 78.46% 78.50% +0.03%
==========================================
Files 145 145
Lines 11479 11484 +5
Branches 3967 3968 +1
==========================================
+ Hits 9007 9015 +8
Misses 1632 1632
+ Partials 840 837 -3
*This pull request uses carry forward flags. Click here to find out more. 🚀 New features to boost your workflow:
|
11 tasks
g1331
added a commit
that referenced
this pull request
May 23, 2026
fix(billing): snapshot 写入加 FK 违例捕获重试,闭环 PR #168 残留的 race
This was referenced May 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
修复生产环境中
request_billing_snapshots写入时出现的 FK 违例:根因
snapshot 持久化是请求主流程的"最后一公里"——尤其在 SSE 流式响应结束后才在
.then(...)里异步触发。如果调用方(route.ts里 8 处persistBillingSnapshotSafely)持有的内存版validApiKey.id在此期间已被外部删除(典型场景:部署冒烟测试创建临时 key、发请求、收响应后立刻删 key),INSERT 时这个 UUID 不再存在于api_keys表,FK 约束失败。onDelete: SET NULL只在"先存在、后被删"时由 DB 触发;救不了"INSERT 时引用已不存在的行"。生产证据
数据库反查同一条
request_logs行:api_key_idNULL(cascade SET NULL 已触发)upstream_idNULL(同上)api_key_namedeploy-smoke-26296857443-keymodelgpt-4.1-smokecreated_at→ snapshotbilled_at时差冒烟测试在 198 ms 窗口内删 key + 删 upstream,snapshot 异步写入时撞 FK。
修复
calculateAndPersistRequestBillingSnapshot入口新增reconcileFkColumnsWithRequestLog:根据requestLogId反查request_logs行,用其api_key_id/upstream_id覆盖 input。request_logs两列都带ON DELETE SET NULL,行内值已是 DB 最终态,天然 FK 安全。影响
api_key_id/upstream_id始终与request_logs行保持一致(即使调用方传入旧 id)。这本就是预期语义,过去因为没显式 reconcile 才会撞 FK。Test plan
pnpm test:run tests/unit/services/billing-cost-service.test.ts—— 13/13 通过(原有 11 + 新增 2)pnpm test:run tests/unit/services/—— 1112/1112 全量单元测试通过,无回归pnpm exec tsc --noEmit通过pnpm lint通过pnpm build通过writes null FK columns when request_logs row was cascade-nulled after key/upstream deletion直接复现并验证生产 race 场景falls back to null FK columns when request_logs row is missing覆盖 request_logs 行不存在的兜底分支failed to persist billing snapshot日志频次回落到 0后续可选改进