sanghyeok An created KAFKA-21298:
------------------------------------

             Summary: Pending offset resets are lost during task recreation, 
causing missing processing results under exactly-once semantics
                 Key: KAFKA-21298
                 URL: https://issues.apache.org/jira/browse/KAFKA-21298
             Project: Kafka
          Issue Type: Bug
            Reporter: sanghyeok An
            Assignee: sanghyeok An


When a transaction is aborted during partial task revocation in exactly-once 
mode, processing results can be lost if a retained task is recreated before its 
pending offset reset is applied.

Records processed in the aborted transaction must be reprocessed from the last 
committed offset. However, if the pending reset information is lost with the 
old task instance, the replacement task continues from the consumer’s current 
position. A subsequent commit can advance the committed offset past the skipped 
records, preventing normal recovery from reprocessing them.

This violates {*}exactly-once semantics{*}, as some input records never have 
their processing results committed.

The following scenario illustrates the issue:
 # *Task A and Task B run on the same StreamThread.*

 ## {*}{*}Task B’s committed offset is {{{}100{}}}. It processes records at 
offsets {{{}100–109{}}}, advancing the consumer position to {{{}110{}}}.

 ## The outputs for these records belong to a transaction that has not yet been 
committed.

 # *The transaction is aborted while only Task A is revoked.*

 ## {*}{*}A rebalance revokes Task A while retaining Task B. During revocation 
handling, {{sendOffsetsToTransaction()}} times out, and the transaction is 
aborted.

 ## Task B’s outputs for offsets {{100–109}} are therefore not committed. Task 
B must reprocess those records starting from committed offset {{{}100{}}}.

 ## Task B is moved into the pending-initialization state, and the partitions 
requiring an offset reset are recorded in the existing task instance. The 
consumer position remains at {{{}110{}}}.

 # *Another assignment is handled before Task B resets its offsets.*

 ## {*}{*}Assignment handling closes the existing Task B awaiting 
initialization and creates a replacement with the same TaskId.

 ## If the pending reset information is not transferred to the replacement 
task, it does not rewind the consumer to offset {{{}100{}}}. Instead, it 
continues processing from offset {{{}110{}}}.

 # *A subsequent transaction commits a higher offset.*

 ## {*}{*}The replacement Task B processes the record at offset {{110}} and 
commits the next offset, {{{}111{}}}.

 ## The processing results for offsets {{100–109}} were discarded by the 
earlier abort, and those records were never reprocessed. Since the committed 
offset has advanced to {{{}111{}}}, subsequent restarts or reassignments do not 
replay them.

The expected behavior is for the replacement task to resume from offset 
{{{}100{}}}, reprocess the records from the aborted transaction, and commit 
their results.

Instead, processing can continue past offsets {{{}100–109{}}}, permanently 
omitting their committed processing results despite exactly-once mode being 
enabled.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to