-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Affects Version(s): 2.2.6 (probably 2.3.x as well)
Use case:
I need to manually control the start offset for topic partitions while still using topic subscriptions; with multiple instances of the application sharing the same groupId.
The solution I plan to use is as follows:
- Start all the instances of the application but without starting the CMLCs.
- Have an external system transmit the desired start offsets to all the instances. Pause all the CMLCs. Start them all. In a
ConsumerSeekAwaremessage listener, seek the topic partitions in theonPartitionsAssignedcallback. - Once the consumer group is stabilized, resume all the CMLCs to start message consumption.
This works mostly fine but I have encountered two issues:
The paused state is not propagated to KafkaMessageListenerContainer on start:
ConcurrentMessageListenerContainer cmlc = ...;
cmlc.pause();
cmlc.start();After executing this code, ConcurrentMessageListenerContainer is paused, but the created KafkaMessageListenerContainer are not.
It's seemingly possible to fix this issue by applying the following modification in ConcurrentMessageListenerContainer:
protected void doStart() {
...
KafkaMessageListenerContainer<K, V> container = new KafkaMessageListenerContainer<>();
...
if (isPaused()) {
container.pause();
}
...
container.start();
this.containers.add(container);
}The first call to KafkaConsumer#poll still returns messages:
KafkaMessageListenerContainer.ListenerConsumer.ListenerConsumerRebalanceListener#onPartitionsAssigned is indirectly called by KafkaMessageListenerContainer.ListenerConsumer#pollAndInvoke, via consumer.poll.
In my case, the KMLC is paused when the rebalance occurs and thus this code is executed:
ListenerConsumer.this.consumerPaused = false;
ListenerConsumer.this.logger.warn("Paused consumer resumed by Kafka due to rebalance; "
+ "the container will pause again before polling, unless the container's "
+ "'paused' property is reset by a custom rebalance listener");However, the call to consumer.poll that caused the rebalance listener to be called still returns messages.
As a quick test, I changed the code above to:
ListenerConsumer.this.consumer.pause(partitions);This yields the desired behavior. The call to consumer.poll does not return messages.
There may be other implications to this change I don't understand ...
(I wonder if there is a similar issue if a seek is performed from ConsumerSeekAware#onPartitionsAssigned while the KMLC is not paused -- messages from before the seek being returned by the call to consumer.poll. I did not test that case though.)