Skip to content

Commit cdcfc58

Browse files
fix: drain buffered ACKs when errorsCh closes before acksCh (#258)
closes #233 ## Summary - `readAcksLoop` defers `close(errorsCh)` before `close(acksCh)` (LIFO), so `errorsCh` closes first. - The `select` in `readAcks` could non-deterministically pick the closed `errorsCh` and return, abandoning buffered ACKs in `acksCh` (buffer size 20). - Lost ACKs leave successful appends in `inflightQueue`, which then time out and get retried on a new session, causing data duplication. - Fix: drain `acksCh` when `errorsCh` closes to process all pending ACKs before returning. ## Test plan - [ ] Verify `go build ./...` passes - [ ] Confirm that under high-throughput pipelined appends, session teardown does not lose buffered ACKs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 0da4976 commit cdcfc58

File tree

1 file changed

+5
-0
lines changed

1 file changed

+5
-0
lines changed

s2/append_session.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,11 @@ func (r *AppendSession) readAcks(session *transportAppendSession) {
423423

424424
case err, ok := <-session.errorsCh:
425425
if !ok {
426+
// errorsCh closes before acksCh (defer order), so
427+
// drain any buffered ACKs before returning.
428+
for ack := range session.acksCh {
429+
r.handleAck(session, ack)
430+
}
426431
return
427432
}
428433
r.handleSessionError(session, err)

0 commit comments

Comments
 (0)