[2.5]fix ConcurrentModificationException (#2560)

* fix ConcurrentModificationException

* kafka consumer improvements

* kafka consumer improvements

* refactored kafka consumer

* refactored kafka consumer
This commit is contained in:
Yevhen Bondarenko 2020-03-31 16:47:43 +03:00 committed by GitHub
parent a6e090ef86
commit b39328c989
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -33,6 +33,8 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -46,6 +48,7 @@ public class TBKafkaConsumerTemplate<T extends TbQueueMsg> implements TbQueueCon
private final TbKafkaDecoder<T> decoder; private final TbKafkaDecoder<T> decoder;
private volatile boolean subscribed; private volatile boolean subscribed;
private volatile Set<TopicPartitionInfo> partitions; private volatile Set<TopicPartitionInfo> partitions;
private final Lock consumerLock;
@Getter @Getter
private final String topic; private final String topic;
@ -71,6 +74,7 @@ public class TBKafkaConsumerTemplate<T extends TbQueueMsg> implements TbQueueCon
this.consumer = new KafkaConsumer<>(props); this.consumer = new KafkaConsumer<>(props);
this.decoder = decoder; this.decoder = decoder;
this.topic = topic; this.topic = topic;
this.consumerLock = new ReentrantLock();
} }
@Override @Override
@ -94,12 +98,16 @@ public class TBKafkaConsumerTemplate<T extends TbQueueMsg> implements TbQueueCon
log.debug("Failed to await subscription", e); log.debug("Failed to await subscription", e);
} }
} else { } else {
try {
consumerLock.lock();
if (!subscribed) { if (!subscribed) {
List<String> topicNames = partitions.stream().map(TopicPartitionInfo::getFullTopicName).collect(Collectors.toList()); List<String> topicNames = partitions.stream().map(TopicPartitionInfo::getFullTopicName).collect(Collectors.toList());
topicNames.forEach(admin::createTopicIfNotExists); topicNames.forEach(admin::createTopicIfNotExists);
consumer.subscribe(topicNames); consumer.subscribe(topicNames);
subscribed = true; subscribed = true;
} }
ConsumerRecords<String, byte[]> records = consumer.poll(Duration.ofMillis(durationInMillis)); ConsumerRecords<String, byte[]> records = consumer.poll(Duration.ofMillis(durationInMillis));
if (records.count() > 0) { if (records.count() > 0) {
List<T> result = new ArrayList<>(); List<T> result = new ArrayList<>();
@ -112,18 +120,34 @@ public class TBKafkaConsumerTemplate<T extends TbQueueMsg> implements TbQueueCon
}); });
return result; return result;
} }
} finally {
consumerLock.unlock();
}
} }
return Collections.emptyList(); return Collections.emptyList();
} }
@Override @Override
public void commit() { public void commit() {
try {
consumerLock.lock();
consumer.commitAsync(); consumer.commitAsync();
} finally {
consumerLock.unlock();
}
} }
@Override @Override
public void unsubscribe() { public void unsubscribe() {
try {
consumerLock.lock();
if (consumer != null) {
consumer.unsubscribe(); consumer.unsubscribe();
consumer.close();
}
} finally {
consumerLock.unlock();
}
} }
public T decode(ConsumerRecord<String, byte[]> record) throws IOException { public T decode(ConsumerRecord<String, byte[]> record) throws IOException {