fix(redis): finish option-2 dedup HLC-4 / ctx-parent parity#901
Conversation
Picks up the two follow-up items noted in claude[bot]'s PR #887 verdict but deferred from that PR: (a) prepareDispatch() takes its bounded ctx from t.server. handlerContext() — the server-lifetime ctx, NOT the caller's dispatchCtx. The reuseCtx fix on PR #887 round 1 corrected runTransactionWithDedup to derive from dispatchCtx; this commit applies the symmetric fix to prepareDispatch so a disconnected client / retryRedisWrite timeout interrupts the prepare+dispatch promptly. Nil-guard falls back to handlerContext for test fixtures that construct a txnContext without setting ctx. (b) dispatchListPushReuse and the listPushCoreWithDedup first- attempt site both shipped before the HLC-4 physical-ceiling migration and were missed in that pass. dispatchExecReuse already uses NextFenced (PR #887 round 1) and so do all first-attempt commit_ts allocations through prepareDispatch and the post-raise SetQueueAttributes etc. These two list-push dedup sites were the last persistence-grade Clock().Next() callers in adapter/redis.go — verified by grep '\.Clock()\.Next\b' adapter/redis.go now returning only the NextFenced variants. Without HLC-4 parity here, a stale-leader window could let the list-push dedup path mint a commit_ts that collides with the successor's freshly-fenced range — defeating the same anomaly class option-2 was introduced to prevent. Caller audit per /loop semantic-change rule ============================================ - prepareDispatch: sole caller is commit() (in this file) and firstExecAttempt (in this file). Both honor defer prepared.cancel() and check len(prepared.elems) == 0; ctx- parent change is additive — same defer-cancel discipline, same error mapping. No external callers. - dispatchListPushReuse: sole caller is listPushCoreWithDedup (in this file). NextFenced error wired through the existing (newLen, drop, err) tuple position; the new error is non- retryable so retryRedisWrite surfaces it directly to the caller — same shape as PR #887 round-1's dispatchExecReuse NextFenced wiring. - listPushCoreWithDedup first-attempt site: surfaces NextFenced error through the existing retryRedisWrite closure return, matching the pattern in prepareDispatch. Validation ========== go test ./adapter/ -run 'ListPushDedup|ExecDedup|StandaloneSetDedup' -race -count=2 -> ok 1.2s gofmt + go vet + golangci-lint run -> 0 issues This PR closes the explicitly-noted follow-up from PR #887's "Note on pre-existing Clock().Next() callers" + the prepareDispatch ctx-parent deviation the round-1 review marked for symmetric treatment. No new functionality.
|
Warning Review limit reached
More reviews will be available in 45 minutes and 26 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request updates adapter/redis.go to improve context cancellation and ensure HLC-4 parity. Specifically, prepareDispatch now derives its timeout-bounded context from the transaction context (t.ctx) instead of the server-lifetime handler context, allowing prompt interruption on client disconnects. Additionally, both dispatchListPushReuse and listPushCoreWithDedup now utilize NextFenced() instead of Next() for commit timestamp allocation to honor the physical-ceiling fence and prevent timestamp collisions. There are no review comments, and I have no additional feedback to provide.
|
@claude review PR-α: option-2 dedup HLC-4 / ctx-parent parity. Follow-up to PR #887 review's noted items. gemini-code-assist already reviewed: "There are no review comments, and I have no additional feedback to provide." — no findings. Verify: (a) prepareDispatch() ctx parent now derives from t.ctx (symmetric with reuseCtx fix on PR #887 round 1); (b) the last two persistence-grade Clock().Next() callers in adapter/redis.go now use NextFenced. |
|
Claude finished @bootjp's task in 3m 22s —— View job Code Review — PR #901
Verification ResultsClaim (a) — Confirmed. The diff replaces: ctx, cancel := context.WithTimeout(t.server.handlerContext(), redisDispatchTimeout)with: parentCtx := t.ctx
if parentCtx == nil {
parentCtx = t.server.handlerContext()
}
ctx, cancel := context.WithTimeout(parentCtx, redisDispatchTimeout)Both production callers always set Claim (b) — All 6 occurrences:
Zero unmitigated 5-Lens Review1. Data Loss No issues. 2. Concurrency / Distributed Failures
3. Performance No hot-path changes. 4. Data Consistency Core correctness: previously, 5. Test Coverage The existing
SummaryBoth stated claims are verified. The ctx-parent fix is symmetric and correct; the two |
claude[bot] PR #901 minor #2 (CLAUDE.md convention): inline comments should state the underlying reason, not reference issue/PR numbers that rot as the codebase evolves. Dropped "PR #887" / "PR #887 round 1" / "PR #887 verdict" / "PR #887 review" attributions from the three doc blocks. The WHY content is kept (ctx-parent symmetry, HLC-4 fence rationale, ErrCeilingExpired non-retryable shape). The PR description is the durable home for the flake-fix lineage and the related PR refs. No behavior change. Comment-only.
|
@claude review Round 1 cleanup (commit 216ca94):
claude[bot] minor #1 (ErrCeilingExpired adapter-level test gap): explicitly out of scope per the verdict ("Low risk", "would lock down the wiring"). Left for follow-up. Comment-only change. |
|
Claude finished @bootjp's task in 1m 55s —— View job Code Review — PR #901 Round 1 Cleanup (commit 216ca94)
VerificationNo Three Doc Block ReviewBlock 1 — Removed: Replaced with: Correct. The WHY (symmetry with Block 2 — Removed: The surrounding comment already explains the rationale (disconnected client, wasted resources). Dropping the dangling Block 3 — Removed: Replaced with: This is the most substantive change, and it's an improvement. The replacement adds concrete error-path behavior (the Ancillary CheckPre-existing
SummaryComment-only change is correct and well-scoped. All three doc blocks have PR-process refs removed; the WHY rationale is fully preserved in each case, and Block 3's replacement adds technically precise detail. No behavior change. LGTM. |
Summary
Picks up the two follow-up items noted in claude[bot]'s PR #887 verdict but deferred from that PR:
(a)
prepareDispatch()ctx-parent symmetric fixprepareDispatch()took its bounded ctx fromt.server.handlerContext()— the server-lifetime ctx, not the caller'sdispatchCtx. ThereuseCtxfix on PR #887 round 1 correctedrunTransactionWithDedupto derive fromdispatchCtx; this PR applies the symmetric fix toprepareDispatchso a disconnected client /retryRedisWritetimeout interrupts the prepare+dispatch promptly.Nil-guard falls back to
handlerContextfor test fixtures that construct atxnContextwithout settingctx.(b) Last two
Clock().Next()callers in adapter/redis.go →NextFenced()dispatchListPushReuseand thelistPushCoreWithDedupfirst-attempt site both shipped before the HLC-4 physical-ceiling migration and were missed in that pass.dispatchExecReusealready usesNextFenced(PR #887 round 1) and so do all first-attemptcommit_tsallocations throughprepareDispatch.These two list-push dedup sites were the last persistence-grade
Clock().Next()callers inadapter/redis.go— verified bygrep '\.Clock()\.Next\b' adapter/redis.gonow returning onlyNextFencedvariants.Without HLC-4 parity here, a stale-leader window could let the list-push dedup path mint a
commit_tsthat collides with the successor's freshly-fenced range — defeating the same anomaly class option-2 was introduced to prevent.Caller audit (per /loop semantic-change rule)
prepareDispatch: sole callers arecommit()andfirstExecAttempt(both in adapter/redis.go). Ctx-parent change is additive; same defer-cancel discipline, same error mapping.dispatchListPushReuse: sole callerlistPushCoreWithDedup. NextFenced error wired through existing(newLen, drop, err)tuple; non-retryable soretryRedisWritesurfaces it directly — matches PR feat(txn-dedup): re-land M3 EXEC reuse on main + close M2 open + multi-mop #887 round-1'sdispatchExecReuseNextFenced wiring.listPushCoreWithDedupfirst-attempt: surfaces NextFenced error through existingretryRedisWriteclosure return.Validation
go test ./adapter/ -run 'ListPushDedup|ExecDedup|StandaloneSetDedup' -race -count=2→ ok 1.2sgofmt+go vet+golangci-lint run→ 0 issuesScope
Closes the two follow-up items explicitly noted in PR #887's round-2 verdict ("Note on pre-existing Clock().Next() callers" +
prepareDispatchctx deviation). No new functionality.