[ 
https://issues.apache.org/jira/browse/FLINK-40586?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18119501#comment-18119501
 ] 

Bhanu Chander Vallabaneni commented on FLINK-40586:
---------------------------------------------------

PR [#309|https://github.com/apache/flink-connector-kafka/pull/309] has been 
rebased and re-scoped, so recording where this ticket now stands.

[~martijnvisser] found that 
[#300|https://github.com/apache/flink-connector-kafka/pull/300] (FLINK-39712, 
open since 7 September) already carried the per-reader dedup this ticket 
describes, and it merged on 21 September. So the fix for the behaviour in the 
summary is on {{main}}, contributed there rather than here, and #309 is reduced 
to the one thing #300 does not cover: clearing the set when a metadata change 
recreates the sub enumerators.

h3. Why the dedup could not land on its own

{{handleNoMoreSplits}} is reached from the proxy callback part way through 
{{addReaderToClusterEnumerators}}, so the first signal goes out before the 
other clusters have assigned. On {{main}} a later signal corrects it; once the 
set makes that the only signal, the reader finishes holding one cluster's 
splits. Four of #300's five tests fail against the original #309 branch for 
exactly that reason, which I confirmed rather than taking on trust. #300's 
deferral is what makes the dedup safe.

h3. The remaining gap, and a finding worth recording

A metadata change closes and recreates every sub enumerator and the reader 
recreates its sub readers, so every sub reader is back to 
{{noMoreSplitsAssignment == false}}. Entries left in the dedup set from the 
previous generation then suppress the signals the new generation needs, and a 
bounded job does not finish. #309 now clears the set at 
{{closeAllEnumeratorsAndContexts()}}.

While writing the test for it I found why this is hard to observe, which is 
relevant to FLINK-31006:

{code:java}
// KafkaSourceEnumerator#checkPartitionChanges
final PartitionChange partitionChange = getPartitionChange(fetchedPartitions, 
!initialDiscoveryFinished);
if (partitionChange.isEmpty()) {
  return;
}
{code}

A *retained* cluster is recreated from state in which its partitions are 
already assigned, so the change is empty and it returns before reaching 
{{signalNoMoreSplits}}. Its new proxy's {{isNoMoreSplits()}} therefore stays 
false, {{allEnumeratorsHaveSignalledNoMoreSplits}} is never true, and 
{{handleNoMoreSplits}} takes the "not ready" branch regardless of the set's 
contents. Instrumented:

{code}
contexts=[kafka-cluster-0, kafka-cluster-1]
noMoreSplitsFlags=[kafka-cluster-0=false, kafka-cluster-1=true]
alreadySignalled=[]
{code}

The test therefore drives a cluster *switchover*, where no sub enumerator is 
retained, every one is new, all of them signal, and the precondition is 
reachable. It fails on {{main}} with the readers signalled once instead of 
twice.

h3. This summary is now stale

The summary still describes the re-signalling that #300 fixed. [~martijnvisser] 
mentioned he would re-scope the ticket; I have left it alone rather than 
editing it myself, but something like "DynamicKafkaSourceEnumerator does not 
clear its no-more-splits dedup set when a metadata change recreates the sub 
enumerators, so a bounded job does not finish" would match what is left. Happy 
for it to be worded however you prefer.

Local verification on the rebased tree: {{DynamicKafkaSourceEnumeratorTest}} 
36/36, {{DynamicKafkaSourceEnumeratorRecoveryTest}} 10/10, 
{{DynamicKafkaSourceReaderTest}} 15/15. {{spotless:check}} and 
{{checkstyle:check}} clean on JDK 17. The workflow run on the PR is at 
{{action_required}} after the force-push, so the JDK 11/17/21 legs need a 
committer to approve them.


> DynamicKafkaSourceEnumerator re-signals NoMoreSplits to already-finished 
> readers on every reader registration, causing "OperatorEvent lost" task 
> failover
> ---------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: FLINK-40586
>                 URL: https://issues.apache.org/jira/browse/FLINK-40586
>             Project: Flink
>          Issue Type: Bug
>          Components: Connectors / Kafka
>    Affects Versions: kafka-3.4.0, kafka-4.0.1, kafka-5.0.0, kafka-5.1.0
>            Reporter: Martijn Visser
>            Assignee: Bhanu Chander Vallabaneni
>            Priority: Major
>              Labels: pull-request-available
>
> DynamicKafkaSourceITTest$IntegrationTests.testIdleReader fails in the weekly 
> CI with
>   org.apache.flink.util.FlinkException: An OperatorEvent from an 
> OperatorCoordinator to a task was
>   lost. Triggering task failover to ensure consistency. Event: 
> '[NoMoreSplitEvent]', targetTask:
>   Source: Tested Source (3/5) - execution #0
>   Caused by: 
> org.apache.flink.runtime.operators.coordination.TaskNotRunningException: Task 
> is not
>   running, but in state FINISHED
> e.g. run 33283936010 job 99183711637 (2026-08-30, main, JDK 11) and run 
> 29667371405 job 88140088972 (2026-07-19, v5.0, Flink 2.1.2, JDK 21); also 
> seen 2026-07-05 (v4.0) and 2026-08-02 (v5.0/2.2.1).
> DynamicKafkaSourceEnumerator.handleNoMoreSplits() calls 
> enumContext.signalNoMoreSplits for every registered reader on every 
> invocation, and it is invoked from addReader, addSplitsBack and 
> tryCompletePendingReaderRegistration without remembering which readers were 
> already signalled. testIdleReader uses parallelism = number of splits + 1, so 
> the idle reader finishes as soon as it receives the first signal; the next 
> reader registration re-sends NoMoreSplitsEvent to the FINISHED task, the 
> event is not loss-tolerant, and the coordinator fails the job.
> This is distinct from FLINK-40362, which fixes the reader-side hang where an 
> idle reader swallows the signal when it arrives before the 
> MetadataUpdateEvent. That fix makes idle readers finish earlier and, if 
> anything, widens this window.



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

Reply via email to