Skip to content

[client] Retry stale out-of-order responses without resetting writer - #4125

Open
litiliu wants to merge 1 commit into
apache:mainfrom
litiliu:fix-idempotent-stale-ooo
Open

[client] Retry stale out-of-order responses without resetting writer#4125
litiliu wants to merge 1 commit into
apache:mainfrom
litiliu:fix-idempotent-stale-ooo

Conversation

@litiliu

@litiliu litiliu commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Purpose

Linked issue: close #4121

Prevent an idempotent writer from being reset when an out-of-order response reflects an older server state and the acknowledged sequence has advanced while the batch was in flight.

Brief change log

  • Snapshot each idempotent batch's last acknowledged sequence on every send attempt.
  • Retry an out-of-order response when the acknowledged sequence has advanced since that attempt was sent.
  • Preserve the existing writer reset behavior when no sequence progress has occurred.
  • Cover stale, genuine, and repeated out-of-order response paths in SenderTest.

Tests

  • ./mvnw -pl fluss-client -DskipITs -Dtest=SenderTest test
    • 26 tests passed.
    • Checkstyle and Spotless passed.

API and Format

No public API or storage format changes.

Documentation

No user-facing documentation changes.

…idempotent writer

An idempotent writer could be fatally reset by a stale OutOfOrderSequence
response, killing all in-flight writes across every bucket.

Failure scenario addressed: with max-inflight > 1 and acks=all,
PutKv/ProduceLog responses are returned in completion order (a bucket's error
result rides along with its request, whose response is gated by the slowest
replicating bucket in that request). A batch (seqN) can transiently fail
(e.g. NotLeaderOrFollower during a leader/partition transition) so its
successor (seqN+1) hits an empty or behind writer state and is rejected with
OutOfOrderSequence. seqN is then retried and acknowledged, advancing
lastAckedBatchSequence, before seqN+1's already-generated out-of-order
response is delivered. At that point the batch looks like the next expected
sequence, so canRetry treated it as an unrecoverable regression and reset the
writer id, which then dropped other in-flight batches with UnknownWriterId.

Fix: snapshot each batch's lastAckedBatchSequence at send time
(WriteBatch.lastAckedSequenceAtSend, set in Sender before dispatch, refreshed
on every send attempt). In IdempotenceManager.canRetry, retry an
OutOfOrderSequence when the acked sequence has advanced since the batch was
sent (current lastAcked > lastAckedSequenceAtSend): that advancement means a
predecessor was acknowledged while the batch was in flight, so the response
is a superseded (stale) one that a reordering surfaced late, and a retry will
observe the advanced state and succeed. A genuine regression shows no such
progress and still resets.

Adds SenderTest cases for the stale (retry, no reset) and genuine (reset)
out-of-order paths, and one asserting the send-time snapshot is refreshed on
retry so a repeated out-of-order response with no new ack still resets.
@litiliu
litiliu marked this pull request as ready for review August 28, 2026 02:16
@litiliu
litiliu marked this pull request as draft August 28, 2026 02:48
@litiliu
litiliu marked this pull request as ready for review August 28, 2026 06:44

@leekeiabstraction leekeiabstraction left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TY for the fix. LGTM, but would recommend @wuchong or @luoyuxia to have a look as well in case I missed anything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[client] Writer job fails after OutOfOrder errors on newly created table partition

2 participants