sanghyeok An created KAFKA-21256:
------------------------------------

             Summary: Assignment callback failure can stall reconciliation in 
the Streams protocol client
                 Key: KAFKA-21256
                 URL: https://issues.apache.org/jira/browse/KAFKA-21256
             Project: Kafka
          Issue Type: Bug
            Reporter: sanghyeok An
            Assignee: sanghyeok An


When Kafka Streams uses {{{}group.protocol=streams{}}}, a failure in the 
{{onTasksAssigned}} callback while processing a new active task assignment can 
leave the member unable to make further reconciliation progress.

The consumer’s partition assignment is updated before the callback runs, 
whereas {{currentAssignment}} is updated only after the callback succeeds. A 
callback failure can therefore leave the actual consumer assignment different 
from the last successfully reconciled assignment.

The next reconciliation attempt detects this mismatch and throws an 
{{{}IllegalStateException{}}}. However, {{reconciliationInProgress}} has 
already been set to {{{}true{}}}, and this exception path does not clear it. 
Subsequent attempts return immediately because they assume another 
reconciliation is still running.

 

*Failure scenario*

Consider a member that is successfully processing assignment A and receives a 
new assignment A+B:
 # Initially, both the consumer assignment and {{currentAssignment}} are A.
 # The consumer’s partition assignment is updated to A+B before invoking the 
assignment callback.
 # The {{onTasksAssigned}} callback throws an exception. The consumer 
assignment remains A+B, while {{currentAssignment}} remains A.
 # Callback failure handling clears the progress flag, allowing another 
reconciliation attempt to begin.
 # The next attempt sets the progress flag again, detects the mismatch between 
the consumer assignment and {{{}currentAssignment{}}}, and throws an exception.
 # The exception leaves the progress flag set. This blocks both retries of the 
same target assignment and processing of newer target assignments.

 
||Stage||Consumer Assignment||Last successufully reconciled assignment
(currentAssignment)||reconciliationInProgress||
|Initial State|A|A|false|
|New assignment applied (callback running)|A + B|A|true|
|After assignment callback failure handling|A + B|A|false|
|After the mismatch exception on the next attempt|A + B|A|true|
|Subsequent attempts|A + B|A|Remains true 
(reconciliation returns immediately)|

 

The same issue can occur when an assignment change includes revocation of 
existing tasks. For example, if A is revoked and the consumer assignment is 
changed to B before B’s assignment callback fails, the consumer assignment 
remains B while the completed assignment remains A. The next attempt encounters 
the same mismatch.

This is particularly problematic for exceptions such as 
{{{}TaskCorruptedException{}}}, which can be handled by an upper layer while 
execution continues. The membership manager can remain stuck independently of 
recovery from the original error.

 

*Impact*

The central issue is that an initial callback failure can escalate into a 
persistent state error that blocks all subsequent assignment processing.
 * *Further polling does not restore progress.* The retained progress flag 
prevents execution from reaching the reconciliation logic.
 * *New assignments cannot be processed.* Even if the broker provides a 
different target assignment, reconciliation remains blocked by the same flag.
 * *Processing of newly assigned partitions may never start while this state 
persists.* Partitions awaiting successful callback completion remain blocked 
from fetching.
 * *A live process does not imply assignment progress.* Thread execution and 
heartbeats may continue after error handling while reconciliation remains 
stalled.

As a result, even a transient or recoverable task error can prevent the member 
from resuming processing through subsequent assignment changes.



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

Reply via email to