You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by or...@apache.org on 2022/04/27 12:57:29 UTC
[camel] branch main updated: CAMEL-18003: fix incorrect concurrent access to the Kafka consumer
This is an automated email from the ASF dual-hosted git repository.
orpiske pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 2f589ad130d CAMEL-18003: fix incorrect concurrent access to the Kafka consumer
2f589ad130d is described below
commit 2f589ad130daacd292fdbb7ef2ef5febf271cf90
Author: Otavio Rodolfo Piske <an...@gmail.com>
AuthorDate: Wed Apr 27 12:53:33 2022 +0200
CAMEL-18003: fix incorrect concurrent access to the Kafka consumer
This prevents the code from throwing ConcurrentModificationException
when suspending
---
.../camel/component/kafka/KafkaFetchRecords.java | 39 ++++++++++++++++++++--
1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaFetchRecords.java b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaFetchRecords.java
index 0c54ea23363..1e5a4be5403 100644
--- a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaFetchRecords.java
+++ b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaFetchRecords.java
@@ -50,6 +50,19 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class KafkaFetchRecords implements Runnable {
+ /*
+ This keeps track of the state the record fetcher is. Because the Kafka consumer is not thread safe, it may take
+ some time between the pause or resume request is triggered and it is actually set.
+ Some of the states may be set but not read. This is done deliberately to avoid the code to enter multiple times
+ the branches that handle the *_REQUESTED states.
+ */
+ private enum State {
+ RUNNING,
+ PAUSE_REQUESTED,
+ PAUSED,
+ RESUME_REQUESTED,
+ }
+
private static final Logger LOG = LoggerFactory.getLogger(KafkaFetchRecords.class);
private final KafkaConsumer kafkaConsumer;
@@ -72,6 +85,8 @@ public class KafkaFetchRecords implements Runnable {
private boolean reconnect; // must be false at init (this is the policy whether to reconnect)
private boolean connected; // this is the state (connected or not)
+ private volatile State state = State.RUNNING;
+
KafkaFetchRecords(KafkaConsumer kafkaConsumer,
BridgeExceptionHandlerToErrorHandler bridge, String topicName, Pattern topicPattern, String id,
Properties kafkaProps, KafkaConsumerListener consumerListener) {
@@ -313,6 +328,7 @@ public class KafkaFetchRecords implements Runnable {
setConnected(false);
}
+ updateTaskState();
}
if (!isConnected()) {
@@ -359,6 +375,23 @@ public class KafkaFetchRecords implements Runnable {
}
}
+ private void updateTaskState() {
+ switch (state) {
+ case PAUSE_REQUESTED:
+ LOG.info("Pausing the consumer as a response to a pause request");
+ consumer.pause(consumer.assignment());
+ state = State.PAUSED;
+ break;
+ case RESUME_REQUESTED:
+ LOG.info("Resuming the consumer as a response to a resume request");
+ consumer.resume(consumer.assignment());
+ state = State.RUNNING;
+ break;
+ default:
+ break;
+ }
+ }
+
private void safeUnsubscribe() {
if (consumer == null) {
return;
@@ -516,7 +549,8 @@ public class KafkaFetchRecords implements Runnable {
* or via JMX
*/
public void pause() {
- consumer.pause(consumer.assignment());
+ LOG.info("A pause request was issued and the consumer thread will pause after current processing has finished");
+ state = State.PAUSE_REQUESTED;
}
/*
@@ -524,6 +558,7 @@ public class KafkaFetchRecords implements Runnable {
* mostly used for directly calling resume from Java code or via JMX
*/
public void resume() {
- consumer.resume(consumer.assignment());
+ LOG.info("A resume request was issued and the consumer thread will resume after current processing has finished");
+ state = State.RESUME_REQUESTED;
}
}