Skip to content

Conversation

@squah-confluent
Copy link
Contributor

Add support for an adaptive batch linger time in the group and share
coordinators. When an adaptive batch linger time is enabled, we no
longer create a timer to flush the current batch. Instead, we append a
flush operation at the end of the event queue so that any currently
queued operations are naturally collected into the batch.

To avoid double flushing from hitting the maximum batch size or
transactional writes, we number batches with an epoch to check whether
the batch has already been flushed.

The group.coordinator.append.linger.ms and
share.coordinator.append.linger.ms configs are extended to allow -1, to
specify an adaptive append linger time. The default for these configs is
also updated to -1.

@github-actions github-actions bot added triage PRs from the community core Kafka Broker KIP-932 Queues for Kafka group-coordinator labels Oct 27, 2025
Comment on lines +28 to +35
private final Deque<CoordinatorEvent> queue;
private boolean inEvent;

public DirectEventProcessor() {
this.queue = new LinkedList<>();
this.inEvent = false;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can now enqueue flush events while in the middle of another event. The flush event must be run after the current event, so we have to introduce a queue here.

.withCoordinatorRuntimeMetrics(mock(CoordinatorRuntimeMetrics.class))
.withCoordinatorMetrics(mock(CoordinatorMetrics.class))
.withSerializer(new StringSerializer())
.withAppendLingerMs(0)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many of the tests in this file run with an adaptive linger time now, except for those with an explicit linger time.

I updated a handful of tests using the ManualEventProcessor to use an append linger time of 0 (preserving the existing behavior) to avoid test churn.

@squah-confluent
Copy link
Contributor Author

The changes are a little long, so it may be easier to review this PR commit by commit, at least for the first 5 commits.

@github-actions github-actions bot removed the triage PRs from the community label Oct 28, 2025
Copy link
Member

@FrankYang0529 FrankYang0529 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM. Leave some minor comments.

Comment on lines 188 to 191
public Builder<S, U> withAppendLingerMs(int appendLingerMs) {
this.appendLingerMs = OptionalInt.of(appendLingerMs);
return this;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the references, this function is only used by test code. Should we remove it and update test cases to use OptionalInt one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, we can remove the method.

Comment on lines +229 to +230
if (appendLingerMs == null)
appendLingerMs = OptionalInt.empty();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the production code, the appendLingerMs input cannot be null. How about we set a default value OptionalInt.empty() to appendLingerMs and remove appendLingerMs == null check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was following the existing pattern in the builder. We don't set a default value for logPrefix, logContext and compression and initialize them in build().

Comment on lines 231 to 232
if (appendLingerMs.isPresent() && appendLingerMs.getAsInt() < -1)
throw new IllegalArgumentException("AppendLinger must be empty or >= 0");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the appendLingerMs is -1, it will be input as OptionalInt.empty(). How about checking the value is >= 0 here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! The check is supposed to reject -1.

@squah-confluent
Copy link
Contributor Author

@FrankYang0529 Thanks for the review! I updated the code. I also added some tests for the config logic.

Copy link
Collaborator

@TaiJuWu TaiJuWu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@dajac dajac self-requested a review November 3, 2025 08:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants