fix(storage): 修复刷新锁固定重试导致的饥饿 - #71
Merged
Merged
Conversation
- 新增 acquireRefreshLock 采用 deadline 与抖动退避 - 刷新锁预算由固定 10 次提升至 15 秒以覆盖 stale 窗口 - 参数化 asyncBackoff 供数据库锁与刷新锁共用
- 完成元数据后的传输关闭改记常规日志不再告警 - 流迭代日志补充会话账号与尝试次数关联字段 - 按 retrying recovered exhausted 等结局分类日志 - 提取 MAX_STREAM_ATTEMPTS 替代硬编码重试上限
Codecov Report❌ Patch coverage is
🚀 New features to boost your workflow:
|
Merged
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
延续 #59 对数据库锁的修复思路,把同一套 deadline + 抖动退避机制补齐到刷新锁;并顺带消除流迭代的一处误报告警、补齐重试可观测性。
1. 刷新锁饥饿(
fix(storage))withRefreshLock此前仍使用固定retries: 10(约 7.5s 预算),而其stale为 15s:ELOCKED(即 TUI 的Lock file is already being held)。修复:新增
acquireRefreshLock,结构与已发布的acquireDatabaseLock完全对称(deadline 循环 +isLockContention判定 + 抖动退避 + 非竞争错误直接抛出)。REFRESH_LOCK_DEADLINE_MS = 15000,沿用 #59 的deadline == stale约定。asyncBackoff参数化后由两把锁共用,数据库锁显式传入原有 25/250ms,有效行为逐字节不变。说明:刷新锁在网络刷新期间被持有,但这不影响修复——proper-lockfile 对存活持有者每
stale/2自动刷新 mtime,活进程不会被误判过期;等待方拿到锁后readLatestAuth直接采纳刚持久化的新 token,不会重复发起网络刷新。因此「等待更久」在此处是正收益。2. 误报告警与可观测性(
fix(streaming))ECONNRESET/terminated)本属正常收尾,此前记为logger.warn造成误报;现改为常规日志并标注outcome: 'ignored_after_completion_metadata'。conversationId/account/accountId/streamAttempt/maxStreamAttempts关联字段。retrying、recovered、exhausted、terminated_after_output。MAX_STREAM_ATTEMPTS常量替代硬编码3。结构化 503 响应体保持不变(
retryable/phase/emittedOutput/code)。不变量保持
Provider id 仍为
kiro-auth;未改动任何锁文件名、getRefreshLockPath/getKeepAliveLockPath、AWS wire strings;互斥语义与锁序(refresh → db)不变。Testing
make ci通过:802 pass, 0 fail, 2244 expect()(基线 797 + 新增 5)。bun run build退出 0。lsp_diagnostics均无诊断。HEAD后跑新增的刷新锁争用测试 →1 fail,8596ms 后抛code: "ELOCKED",报错文件正是.kiro-refresh-*.lock,证明旧的 7.5s 预算确实会饥饿;恢复实现后 →1 pass(9.03s)。retrying/recovered日志关联、exhausted日志且 503 响应不变、terminated_after_output、完成元数据后传输关闭不产生失败告警。取舍说明:刷新锁争用测试包含约 8.5s 真实等待(超时上限 12s)。若只等 3s,旧实现也能通过、测试将失去鉴别力。代价是整套测试从约 17s 增至约 23s。
Blocked features
无。ELOCKED 致命边界(
token-refresher.ts终态 throw 及若干batchSave)本次未触碰,与 #59 对数据库路径的处理策略保持一致。