Repository navigation
Kafka Streams runner: target flush markers across repartition topics - #40186
Merged
Merged
Conversation
Rename GroupByKeyBroadcastPartitioner to KStreamsPayloadPartitioner. It sends a flush to the partitions the marker names, and fails if the topic does not have internalParallelism partitions. ShuffleByKeyProcessor picks those partitions: upstream partition i of U addresses [i*D/U, (i+1)*D/U) of the D downstream partitions, so every downstream partition gets exactly one flush. An instance with nothing to address forwards no marker. Part of apache#39633.
Contributor
Author
|
R: @je-ik |
Contributor
|
Stopping reviewer notifications for this pull request: review requested by someone other than the bot, ceding control. If you'd like to restart, comment |
je-ik
reviewed
Sep 21, 2026
je-ik
left a comment
Contributor
There was a problem hiding this comment.
I'm a little confused about how we do actually ensure that the elements are really actually emitted to the target partitions? I.e. if there are multiple partitions, how do we make sure the element is correctly duplicated across them?
Kafka Streams writes one copy of a record to each partition that StreamPartitioner.partitions() returns. Say so where the shuffle forwards a flush, and add a broker test that sends a flush for partitions 1 and 2 of a four partition topic and checks it lands once on each and nowhere else. TopologyTestDriver cannot show this, since it reports every topic as having one partition.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Second PR toward bundles bounded by time (#39633), after #40068. It makes the shuffle and the repartition partitioner handle a flush marker. Nothing emits markers yet, so there is no behaviour change.
What changed
GroupByKeyBroadcastPartitioneris renamed toKStreamsPayloadPartitioner, since it no longer only broadcasts. Data is still hashed by key and watermarks still go to every partition. A flush goes to exactly the partitions it names.ShuffleByKeyProcessorpicks those partitions. Upstream partitioniofUaddresses downstream partitions[floor(i*D/U), floor((i+1)*D/U))ofD. Over allithis covers every downstream partition exactly once, for fan-out, fan-in and equal counts, so each downstream partition gets one flush per interval and not one per upstream partition. It only depends on partition numbers, so a rebalance does not change it.internalParallelismpartitions. The targets are computed for that count, so on a topic left by an earlier run with a different parallelism they would point at partitions that don't exist, or skip some. The topic manager reuses an existing topic without checking its partition count, so nothing catches this earlier today. Handling stale topics properly belongs to Kafka Streams runner: lifecycle management for runner-created topics #39566.Order of the remaining PRs
I swapped the last two compared to #40068. Today
ExecutableStageProcessorandWindowedGroupByKeyProcessorwould throw on a flush, because each treats anything that is not one kind as the other kind. So consumers have to handle the marker before any source emits it:ExecutableStageProcessorcloses its bundle and forwards the marker,WindowedGroupByKeyProcessorforwards it.StageOutputProcessorandFlattenProcessoralready pass it through.maxBundleTimeMs.One open question for step 4: a marker created by a source has no edge yet, but
KStreamsPayload.flushdoes not accept empty targets. The shuffle recomputes targets anyway, so what a source puts there is ignored. I'd rather settle that in step 4 than change the payload now.Testing
Both pass, 119 unit tests and 59 ValidatesRunner tests. New tests:
KStreamsPayloadPartitionerTest(watermark broadcast, flush targets, data by key, keyless data, partition count mismatch) and four inShuffleByKeyProcessorTest, including one that checks every downstream partition is hit exactly once for several upstream/downstream shapes. I checked they catch real mistakes: an off-by-one in the range rule plus removing the partition count check fails five of them, and forwarding a flush with no targets fails the fan-in test.