Search in sources :

Example 1 with KafkaMessage

use of io.micronaut.configuration.kafka.KafkaMessage in project micronaut-kafka by micronaut-projects.

the class KafkaConsumerProcessor method handleResultFlux.

@SuppressWarnings({ "SubscriberImplementation", "unchecked" })
private void handleResultFlux(ConsumerState consumerState, ExecutableMethod<?, ?> method, ConsumerRecord<?, ?> consumerRecord, Flux<?> resultFlowable, boolean isBlocking, ConsumerRecords<?, ?> consumerRecords) {
    Flux<RecordMetadata> recordMetadataProducer = resultFlowable.flatMap((Function<Object, Publisher<RecordMetadata>>) value -> {
        if (consumerState.sendToDestinationTopics != null) {
            Object key = consumerRecord.key();
            if (value != null) {
                Producer kafkaProducer;
                if (consumerState.useSendOffsetsToTransaction) {
                    kafkaProducer = transactionalProducerRegistry.getTransactionalProducer(consumerState.producerClientId, consumerState.producerTransactionalId, Argument.of(byte[].class), Argument.of(Object.class));
                } else {
                    kafkaProducer = producerRegistry.getProducer(consumerState.producerClientId == null ? consumerState.groupId : consumerState.producerClientId, Argument.of((Class) (key != null ? key.getClass() : byte[].class)), Argument.of(value.getClass()));
                }
                return Flux.create(emitter -> {
                    try {
                        if (consumerState.useSendOffsetsToTransaction) {
                            try {
                                LOG.trace("Beginning transaction for producer: {}", consumerState.producerTransactionalId);
                                kafkaProducer.beginTransaction();
                            } catch (ProducerFencedException e) {
                                handleProducerFencedException(kafkaProducer, e);
                            }
                        }
                        for (String destinationTopic : consumerState.sendToDestinationTopics) {
                            if (consumerState.isMessagesIterableReturnType) {
                                Iterable<KafkaMessage> messages = (Iterable<KafkaMessage>) value;
                                for (KafkaMessage message : messages) {
                                    ProducerRecord record = createFromMessage(destinationTopic, message);
                                    kafkaProducer.send(record, (metadata, exception) -> {
                                        if (exception != null) {
                                            emitter.error(exception);
                                        } else {
                                            emitter.next(metadata);
                                        }
                                    });
                                }
                            } else {
                                ProducerRecord record;
                                if (consumerState.isMessageReturnType) {
                                    record = createFromMessage(destinationTopic, (KafkaMessage) value);
                                } else {
                                    record = new ProducerRecord(destinationTopic, null, key, value, consumerRecord.headers());
                                }
                                LOG.trace("Sending record: {} for producer: {} {}", record, kafkaProducer, consumerState.producerTransactionalId);
                                kafkaProducer.send(record, (metadata, exception) -> {
                                    if (exception != null) {
                                        emitter.error(exception);
                                    } else {
                                        emitter.next(metadata);
                                    }
                                });
                            }
                        }
                        if (consumerState.useSendOffsetsToTransaction) {
                            Map<TopicPartition, OffsetAndMetadata> offsetsToCommit = new HashMap<>();
                            for (TopicPartition partition : consumerRecords.partitions()) {
                                List<? extends ConsumerRecord<?, ?>> partitionedRecords = consumerRecords.records(partition);
                                long offset = partitionedRecords.get(partitionedRecords.size() - 1).offset();
                                offsetsToCommit.put(partition, new OffsetAndMetadata(offset + 1));
                            }
                            try {
                                LOG.trace("Sending offsets: {} to transaction for producer: {} and customer group id: {}", offsetsToCommit, consumerState.producerTransactionalId, consumerState.groupId);
                                kafkaProducer.sendOffsetsToTransaction(offsetsToCommit, consumerState.groupId);
                                LOG.trace("Committing transaction for producer: {}", consumerState.producerTransactionalId);
                                kafkaProducer.commitTransaction();
                                LOG.trace("Committed transaction for producer: {}", consumerState.producerTransactionalId);
                            } catch (ProducerFencedException e) {
                                handleProducerFencedException(kafkaProducer, e);
                            }
                        }
                        emitter.complete();
                    } catch (Exception e) {
                        if (consumerState.useSendOffsetsToTransaction) {
                            try {
                                LOG.trace("Aborting transaction for producer: {} because of error: {}", consumerState.producerTransactionalId, e.getMessage());
                                kafkaProducer.abortTransaction();
                            } catch (ProducerFencedException ex) {
                                handleProducerFencedException(kafkaProducer, ex);
                            }
                        }
                        emitter.error(e);
                    }
                });
            }
            return Flux.empty();
        }
        return Flux.empty();
    });
    recordMetadataProducer = recordMetadataProducer.onErrorResume((Function<Throwable, Publisher<RecordMetadata>>) throwable -> {
        handleException(consumerState.consumerBean, new KafkaListenerException("Error occurred processing record [" + consumerRecord + "] with Kafka reactive consumer [" + method + "]: " + throwable.getMessage(), throwable, consumerState.consumerBean, consumerState.kafkaConsumer, consumerRecord));
        if (consumerState.redelivery) {
            LOG.debug("Attempting redelivery of record [{}] following error", consumerRecord);
            Object key = consumerRecord.key();
            Object value = consumerRecord.value();
            if (key != null && value != null) {
                Producer kafkaProducer = producerRegistry.getProducer(consumerState.producerClientId == null ? consumerState.groupId : consumerState.producerClientId, Argument.of(key.getClass()), Argument.of(value.getClass()));
                ProducerRecord record = new ProducerRecord(consumerRecord.topic(), consumerRecord.partition(), key, value, consumerRecord.headers());
                return producerSend(consumerState, kafkaProducer, record).doOnError(ex -> {
                    handleException(consumerState.consumerBean, new KafkaListenerException("Redelivery failed for record [" + consumerRecord + "] with Kafka reactive consumer [" + method + "]: " + throwable.getMessage(), throwable, consumerState.consumerBean, consumerState.kafkaConsumer, consumerRecord));
                });
            }
        }
        return Flux.empty();
    });
    if (isBlocking) {
        List<RecordMetadata> listRecords = recordMetadataProducer.collectList().block();
        LOG.trace("Method [{}] produced record metadata: {}", method, listRecords);
    } else {
        recordMetadataProducer.subscribe(recordMetadata -> LOG.trace("Method [{}] produced record metadata: {}", logMethod(method), recordMetadata));
    }
}
Also used : Topic(io.micronaut.configuration.kafka.annotation.Topic) Publishers(io.micronaut.core.async.publisher.Publishers) Bindable(io.micronaut.core.bind.annotation.Bindable) Arrays(java.util.Arrays) KafkaAcknowledgement(io.micronaut.configuration.kafka.KafkaAcknowledgement) ConsumerRecords(org.apache.kafka.clients.consumer.ConsumerRecords) MessagingSystemException(io.micronaut.messaging.exceptions.MessagingSystemException) ConsumerRecordBinderRegistry(io.micronaut.configuration.kafka.bind.ConsumerRecordBinderRegistry) StringDeserializer(org.apache.kafka.common.serialization.StringDeserializer) Duration(java.time.Duration) Map(java.util.Map) OffsetCommitCallback(org.apache.kafka.clients.consumer.OffsetCommitCallback) ArgumentUtils(io.micronaut.core.util.ArgumentUtils) DefaultExecutableBinder(io.micronaut.core.bind.DefaultExecutableBinder) Singleton(jakarta.inject.Singleton) Set(java.util.Set) Acknowledgement(io.micronaut.messaging.Acknowledgement) ConsumerConfig(org.apache.kafka.clients.consumer.ConsumerConfig) RecordMetadata(org.apache.kafka.clients.producer.RecordMetadata) ErrorStrategy(io.micronaut.configuration.kafka.annotation.ErrorStrategy) ExecutableMethodProcessor(io.micronaut.context.processor.ExecutableMethodProcessor) StandardCharsets(java.nio.charset.StandardCharsets) KafkaKey(io.micronaut.configuration.kafka.annotation.KafkaKey) SerdeRegistry(io.micronaut.configuration.kafka.serde.SerdeRegistry) ConsumerRecord(org.apache.kafka.clients.consumer.ConsumerRecord) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) AbstractKafkaConsumerConfiguration(io.micronaut.configuration.kafka.config.AbstractKafkaConsumerConfiguration) ProducerRegistry(io.micronaut.configuration.kafka.ProducerRegistry) MessageBody(io.micronaut.messaging.annotation.MessageBody) ConsumerRegistry(io.micronaut.configuration.kafka.ConsumerRegistry) RecordHeader(org.apache.kafka.common.header.internals.RecordHeader) KafkaMessage(io.micronaut.configuration.kafka.KafkaMessage) Nullable(io.micronaut.core.annotation.Nullable) ReturnType(io.micronaut.core.type.ReturnType) Argument(io.micronaut.core.type.Argument) Blocking(io.micronaut.core.annotation.Blocking) ByteArrayDeserializer(org.apache.kafka.common.serialization.ByteArrayDeserializer) Properties(java.util.Properties) Producer(org.apache.kafka.clients.producer.Producer) OffsetStrategy(io.micronaut.configuration.kafka.annotation.OffsetStrategy) Publisher(org.reactivestreams.Publisher) KafkaListenerException(io.micronaut.configuration.kafka.exceptions.KafkaListenerException) Mono(reactor.core.publisher.Mono) SendTo(io.micronaut.messaging.annotation.SendTo) Flux(reactor.core.publisher.Flux) CommitFailedException(org.apache.kafka.clients.consumer.CommitFailedException) TaskScheduler(io.micronaut.scheduling.TaskScheduler) BeanDefinition(io.micronaut.inject.BeanDefinition) BeanContext(io.micronaut.context.BeanContext) ArrayUtils(io.micronaut.core.util.ArrayUtils) LoggerFactory(org.slf4j.LoggerFactory) PreDestroy(javax.annotation.PreDestroy) TaskExecutors(io.micronaut.scheduling.TaskExecutors) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Locale(java.util.Locale) KafkaListenerExceptionHandler(io.micronaut.configuration.kafka.exceptions.KafkaListenerExceptionHandler) ApplicationConfiguration(io.micronaut.runtime.ApplicationConfiguration) NameUtils(io.micronaut.core.naming.NameUtils) Consumer(org.apache.kafka.clients.consumer.Consumer) TopicPartition(org.apache.kafka.common.TopicPartition) WakeupException(org.apache.kafka.common.errors.WakeupException) Collection(java.util.Collection) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Qualifiers(io.micronaut.inject.qualifiers.Qualifiers) UUID(java.util.UUID) Collectors(java.util.stream.Collectors) StringUtils(io.micronaut.core.util.StringUtils) ConsumerRebalanceListener(org.apache.kafka.clients.consumer.ConsumerRebalanceListener) List(java.util.List) ProducerFencedException(org.apache.kafka.common.errors.ProducerFencedException) OffsetAndMetadata(org.apache.kafka.clients.consumer.OffsetAndMetadata) Optional(java.util.Optional) Pattern(java.util.regex.Pattern) Named(jakarta.inject.Named) KafkaListener(io.micronaut.configuration.kafka.annotation.KafkaListener) BatchConsumerRecordsBinderRegistry(io.micronaut.configuration.kafka.bind.batch.BatchConsumerRecordsBinderRegistry) ProducerRecord(org.apache.kafka.clients.producer.ProducerRecord) ErrorStrategyValue(io.micronaut.configuration.kafka.annotation.ErrorStrategyValue) ScheduledExecutorTaskScheduler(io.micronaut.scheduling.ScheduledExecutorTaskScheduler) TransactionalProducerRegistry(io.micronaut.configuration.kafka.TransactionalProducerRegistry) KafkaDefaultConfiguration(io.micronaut.configuration.kafka.config.KafkaDefaultConfiguration) HashMap(java.util.HashMap) Scheduler(reactor.core.scheduler.Scheduler) Function(java.util.function.Function) ExecutableMethod(io.micronaut.inject.ExecutableMethod) HashSet(java.util.HashSet) ExecutableBinder(io.micronaut.core.bind.ExecutableBinder) Requires(io.micronaut.context.annotation.Requires) Schedulers(reactor.core.scheduler.Schedulers) BoundExecutable(io.micronaut.core.bind.BoundExecutable) ExecutorService(java.util.concurrent.ExecutorService) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) OffsetReset(io.micronaut.configuration.kafka.annotation.OffsetReset) NonNull(io.micronaut.core.annotation.NonNull) IsolationLevel(org.apache.kafka.common.IsolationLevel) CollectionUtils(io.micronaut.core.util.CollectionUtils) DefaultKafkaConsumerConfiguration(io.micronaut.configuration.kafka.config.DefaultKafkaConsumerConfiguration) Collections(java.util.Collections) ConsumerAware(io.micronaut.configuration.kafka.ConsumerAware) KafkaMessage(io.micronaut.configuration.kafka.KafkaMessage) Publisher(org.reactivestreams.Publisher) ConsumerRecord(org.apache.kafka.clients.consumer.ConsumerRecord) MessagingSystemException(io.micronaut.messaging.exceptions.MessagingSystemException) KafkaListenerException(io.micronaut.configuration.kafka.exceptions.KafkaListenerException) CommitFailedException(org.apache.kafka.clients.consumer.CommitFailedException) WakeupException(org.apache.kafka.common.errors.WakeupException) ProducerFencedException(org.apache.kafka.common.errors.ProducerFencedException) ProducerFencedException(org.apache.kafka.common.errors.ProducerFencedException) RecordMetadata(org.apache.kafka.clients.producer.RecordMetadata) KafkaListenerException(io.micronaut.configuration.kafka.exceptions.KafkaListenerException) Function(java.util.function.Function) Producer(org.apache.kafka.clients.producer.Producer) TopicPartition(org.apache.kafka.common.TopicPartition) ProducerRecord(org.apache.kafka.clients.producer.ProducerRecord) OffsetAndMetadata(org.apache.kafka.clients.consumer.OffsetAndMetadata) List(java.util.List) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap)

Aggregations

ConsumerAware (io.micronaut.configuration.kafka.ConsumerAware)1 ConsumerRegistry (io.micronaut.configuration.kafka.ConsumerRegistry)1 KafkaAcknowledgement (io.micronaut.configuration.kafka.KafkaAcknowledgement)1 KafkaMessage (io.micronaut.configuration.kafka.KafkaMessage)1 ProducerRegistry (io.micronaut.configuration.kafka.ProducerRegistry)1 TransactionalProducerRegistry (io.micronaut.configuration.kafka.TransactionalProducerRegistry)1 ErrorStrategy (io.micronaut.configuration.kafka.annotation.ErrorStrategy)1 ErrorStrategyValue (io.micronaut.configuration.kafka.annotation.ErrorStrategyValue)1 KafkaKey (io.micronaut.configuration.kafka.annotation.KafkaKey)1 KafkaListener (io.micronaut.configuration.kafka.annotation.KafkaListener)1 OffsetReset (io.micronaut.configuration.kafka.annotation.OffsetReset)1 OffsetStrategy (io.micronaut.configuration.kafka.annotation.OffsetStrategy)1 Topic (io.micronaut.configuration.kafka.annotation.Topic)1 ConsumerRecordBinderRegistry (io.micronaut.configuration.kafka.bind.ConsumerRecordBinderRegistry)1 BatchConsumerRecordsBinderRegistry (io.micronaut.configuration.kafka.bind.batch.BatchConsumerRecordsBinderRegistry)1 AbstractKafkaConsumerConfiguration (io.micronaut.configuration.kafka.config.AbstractKafkaConsumerConfiguration)1 DefaultKafkaConsumerConfiguration (io.micronaut.configuration.kafka.config.DefaultKafkaConsumerConfiguration)1 KafkaDefaultConfiguration (io.micronaut.configuration.kafka.config.KafkaDefaultConfiguration)1 KafkaListenerException (io.micronaut.configuration.kafka.exceptions.KafkaListenerException)1 KafkaListenerExceptionHandler (io.micronaut.configuration.kafka.exceptions.KafkaListenerExceptionHandler)1