Martijn Visser created FLINK-40585:
--------------------------------------
Summary: KafkaSinkITCase.rescaleListing fails intermittently after
scale-up-then-down: restored transactions fenced on commit, only a subset of
records readable
Key: FLINK-40585
URL: https://issues.apache.org/jira/browse/FLINK-40585
Project: Flink
Issue Type: Bug
Components: Connectors / Kafka
Affects Versions: kafka-4.0.1, kafka-5.1.0
Reporter: Martijn Visser
- run 30181683657, job 89739208487 (2026-07-26, main, Flink 2.2-SNAPSHOT, JDK
21), rescaleListing[4] (3 -> 5 -> 3): actual [334L, 335L, 336L, 667L, 668L,
669L, 0L, 1L, 2L, 3L, 4L, 337L, 338L, 670L, 671L], expected [0L .. 999L].
- run 31916828021, job 95089941850 (2026-08-16, v4.0, Flink 2.0.2, JDK 21),
rescaleListing[3] (2 -> 5 -> 2): 966 of 1000 records missing.
The test uses TransactionNamingStrategy.POOLING; job 1 (firstPrefix) fails in
the async checkpoint phase, job 2 (secondPrefix) restores at a different
parallelism and fails the same way, job 3 (thirdPrefix) restores from job 2's
checkpoint at the original parallelism.
What the job-3 log shows (89739208487, 01:07:53):
.648 committers resume secondPrefix-0-0 / -2-0 / -4-0 with the restored
producerId and epoch 0
.756 KafkaCommitter WARN "Unable to commit transaction ... because its producer
is already fenced" for all three (ProducerFencedException), ~100 ms later
.770 writers start "Aborting lingering transactions with prefixes [thirdPrefix,
secondPrefix]
using LISTING"; the listing finds only secondPrefix-x-1 open, i.e. the -x-0
transactions
were no longer open on the broker at that point, and the precommitted ids were
correctly
skipped by TransactionAbortStrategyImpl
01:08:09 the retry creates fresh producers (initTransactions, epoch 2) and the
commit fails
again with ERROR.
So the epoch of the precommitted transactions had already moved past 0 before
job 3 started. Two readings, and the log cannot separate them:
(a) benign: job 2 had already committed them on checkpoint completion
(RecordFetcher saw the notification), the POOLING recycle bumped the epoch, and
the fenced retry is the documented "expected in some cases" path. The records
are then in the topic, and the missing data is a read_committed artefact:
KafkaUtil.drainAllRecordsFromTopic snapshots endOffsets once (the LSO), and job
3 fails with "Planned exception" while its thirdPrefix-x-1 transactions stay
open (the writer deliberately does not abort on close, ExactlyOnceKafkaWriter
~line 281), pinning the LSO.
(b) real: the transactions were never committed and the committer dropped them
via
signalFailedWithKnownReason, which the warning text itself says signals data
loss.
Reading (a) predicts that draining with read_uncommitted, or aborting the
leftover thirdPrefix transactions before draining, would show all 1000 records;
reading (b) predicts they are absent. That single check decides it and should
be the first step. Until then treat as Major, not Critical; if (b) holds, raise
to Blocker and it is a FLIP-511 recovery bug.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)