Search in sources :

Example 6 with ExecutableMethod

use of io.micronaut.inject.ExecutableMethod in project micronaut-kafka by micronaut-projects.

the class KafkaConsumerProcessor method createConsumerThreadPollLoop.

private void createConsumerThreadPollLoop(final ExecutableMethod<?, ?> method, final ConsumerState consumerState) {
    final boolean isBatch = method.isTrue(KafkaListener.class, "batch");
    final Duration pollTimeout = method.getValue(KafkaListener.class, "pollTimeout", Duration.class).orElseGet(() -> Duration.ofMillis(100));
    final Optional<Argument<?>> consumerArg = Arrays.stream(method.getArguments()).filter(arg -> Consumer.class.isAssignableFrom(arg.getType())).findFirst();
    final Optional<Argument<?>> ackArg = Arrays.stream(method.getArguments()).filter(arg -> Acknowledgement.class.isAssignableFrom(arg.getType())).findFirst();
    try (Consumer<?, ?> kafkaConsumer = consumerState.kafkaConsumer) {
        final boolean trackPartitions = ackArg.isPresent() || consumerState.offsetStrategy == OffsetStrategy.SYNC_PER_RECORD || consumerState.offsetStrategy == OffsetStrategy.ASYNC_PER_RECORD;
        final Map<Argument<?>, Object> boundArguments = new HashMap<>(2);
        consumerArg.ifPresent(argument -> boundArguments.put(argument, kafkaConsumer));
        // noinspection InfiniteLoopStatement
        while (true) {
            consumerState.assignments = Collections.unmodifiableSet(kafkaConsumer.assignment());
            if (consumerState.autoPaused) {
                consumerState.pause(consumerState.assignments);
                kafkaConsumer.pause(consumerState.assignments);
            }
            boolean failed = true;
            try {
                consumerState.pauseTopicPartitions();
                final ConsumerRecords<?, ?> consumerRecords = kafkaConsumer.poll(pollTimeout);
                failed = false;
                consumerState.resumeTopicPartitions();
                if (consumerRecords == null || consumerRecords.count() <= 0) {
                    // No consumer records to process
                    continue;
                }
                if (isBatch) {
                    failed = !processConsumerRecordsAsBatch(consumerState, method, boundArguments, consumerRecords);
                } else {
                    failed = !processConsumerRecords(consumerState, method, boundArguments, trackPartitions, ackArg, consumerRecords);
                }
                if (!failed) {
                    if (consumerState.offsetStrategy == OffsetStrategy.SYNC) {
                        try {
                            kafkaConsumer.commitSync();
                        } catch (CommitFailedException e) {
                            handleException(consumerState, null, e);
                        }
                    } else if (consumerState.offsetStrategy == OffsetStrategy.ASYNC) {
                        kafkaConsumer.commitAsync(resolveCommitCallback(consumerState.consumerBean));
                    }
                }
            } catch (WakeupException e) {
                try {
                    if (!failed && consumerState.offsetStrategy != OffsetStrategy.DISABLED) {
                        kafkaConsumer.commitSync();
                    }
                } catch (Throwable ex) {
                    LOG.warn("Error committing Kafka offsets on shutdown: {}", ex.getMessage(), ex);
                }
                throw e;
            } catch (Throwable e) {
                handleException(consumerState, null, e);
            }
        }
    } catch (WakeupException e) {
    // ignore for shutdown
    }
}
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) Argument(io.micronaut.core.type.Argument) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) Duration(java.time.Duration) WakeupException(org.apache.kafka.common.errors.WakeupException) KafkaListener(io.micronaut.configuration.kafka.annotation.KafkaListener) CommitFailedException(org.apache.kafka.clients.consumer.CommitFailedException)

Example 7 with ExecutableMethod

use of io.micronaut.inject.ExecutableMethod 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: {}", 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)

Example 8 with ExecutableMethod

use of io.micronaut.inject.ExecutableMethod in project micronaut-nats by micronaut-projects.

the class NatsConsumerAdvice method process.

@Override
public void process(BeanDefinition<?> beanDefinition, ExecutableMethod<?, ?> method) {
    if (method.hasAnnotation(NatsListener.class)) {
        AnnotationValue<Subject> subjectAnn = method.getAnnotation(Subject.class);
        if (subjectAnn != null) {
            String subject = subjectAnn.getRequiredValue(String.class);
            String connectionName = method.findAnnotation(NatsConnection.class).flatMap(conn -> conn.get("connection", String.class)).orElse(NatsConnection.DEFAULT_CONNECTION);
            io.micronaut.context.Qualifier<Object> qualifer = beanDefinition.getAnnotationTypeByStereotype("javax.inject.Qualifier").map(type -> Qualifiers.byAnnotation(beanDefinition, type)).orElse(null);
            Class<Object> beanType = (Class<Object>) beanDefinition.getBeanType();
            Class<?> returnTypeClass = method.getReturnType().getType();
            boolean isVoid = returnTypeClass == Void.class || returnTypeClass == void.class;
            Object bean = beanContext.findBean(beanType, qualifer).orElseThrow(() -> new MessageListenerException("Could not find the bean to execute the method " + method));
            Connection connection = beanContext.getBean(Connection.class, Qualifiers.byName(connectionName));
            DefaultExecutableBinder<Message> binder = new DefaultExecutableBinder<>();
            Dispatcher ds = connection.createDispatcher(msg -> {
                BoundExecutable boundExecutable = null;
                try {
                    boundExecutable = binder.bind(method, binderRegistry, msg);
                } catch (Throwable e) {
                    handleException(new NatsListenerException("An error occurred binding the message to the method", e, bean, msg));
                }
                if (boundExecutable != null) {
                    Object returnedValue = boundExecutable.invoke(bean);
                    if (!isVoid && StringUtils.isNotEmpty(msg.getReplyTo())) {
                        byte[] converted = null;
                        if (returnedValue != null) {
                            NatsMessageSerDes serDes = serDesRegistry.findSerdes(method.getReturnType().asArgument()).map(NatsMessageSerDes.class::cast).orElseThrow(() -> new NatsListenerException(String.format("Could not find a serializer for the body argument of type [%s]", returnedValue.getClass().getName()), bean, msg));
                            converted = serDes.serialize(returnedValue);
                        }
                        connection.publish(msg.getReplyTo(), converted);
                    }
                }
            });
            Optional<String> queueOptional = subjectAnn.get("queue", String.class);
            if (queueOptional.isPresent() && !queueOptional.get().isEmpty()) {
                ds.subscribe(subject, queueOptional.get());
            } else {
                ds.subscribe(subject);
            }
            consumerDispatchers.put(ds, subject);
        }
    }
}
Also used : NatsBinderRegistry(io.micronaut.nats.bind.NatsBinderRegistry) BeanContext(io.micronaut.context.BeanContext) MessageListenerException(io.micronaut.messaging.exceptions.MessageListenerException) NatsConnection(io.micronaut.nats.annotation.NatsConnection) Dispatcher(io.nats.client.Dispatcher) NatsMessageSerDes(io.micronaut.nats.serdes.NatsMessageSerDes) ExecutableMethod(io.micronaut.inject.ExecutableMethod) NatsListenerExceptionHandler(io.micronaut.nats.exception.NatsListenerExceptionHandler) Message(io.nats.client.Message) NatsListenerException(io.micronaut.nats.exception.NatsListenerException) NatsMessageSerDesRegistry(io.micronaut.nats.serdes.NatsMessageSerDesRegistry) Map(java.util.Map) Connection(io.nats.client.Connection) BoundExecutable(io.micronaut.core.bind.BoundExecutable) DefaultExecutableBinder(io.micronaut.core.bind.DefaultExecutableBinder) Iterator(java.util.Iterator) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Qualifiers(io.micronaut.inject.qualifiers.Qualifiers) Singleton(jakarta.inject.Singleton) ExecutableMethodProcessor(io.micronaut.context.processor.ExecutableMethodProcessor) StringUtils(io.micronaut.core.util.StringUtils) NatsListener(io.micronaut.nats.annotation.NatsListener) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) Subject(io.micronaut.nats.annotation.Subject) Optional(java.util.Optional) BeanDefinition(io.micronaut.inject.BeanDefinition) Message(io.nats.client.Message) Dispatcher(io.nats.client.Dispatcher) NatsMessageSerDes(io.micronaut.nats.serdes.NatsMessageSerDes) MessageListenerException(io.micronaut.messaging.exceptions.MessageListenerException) DefaultExecutableBinder(io.micronaut.core.bind.DefaultExecutableBinder) NatsConnection(io.micronaut.nats.annotation.NatsConnection) Connection(io.nats.client.Connection) Subject(io.micronaut.nats.annotation.Subject) BoundExecutable(io.micronaut.core.bind.BoundExecutable) NatsListenerException(io.micronaut.nats.exception.NatsListenerException)

Example 9 with ExecutableMethod

use of io.micronaut.inject.ExecutableMethod in project micronaut-gcp by micronaut-projects.

the class PubSubConsumerAdvice method process.

@Override
public void process(BeanDefinition<?> beanDefinition, ExecutableMethod<?, ?> method) {
    if (beanDefinition.hasDeclaredAnnotation(PubSubListener.class)) {
        AnnotationValue<Subscription> subscriptionAnnotation = method.getAnnotation(Subscription.class);
        io.micronaut.context.Qualifier<Object> qualifier = beanDefinition.getAnnotationTypeByStereotype(Qualifier.class).map(type -> Qualifiers.byAnnotation(beanDefinition, type)).orElse(null);
        boolean hasAckArg = Arrays.stream(method.getArguments()).anyMatch(arg -> Acknowledgement.class.isAssignableFrom(arg.getType()));
        Class<Object> beanType = (Class<Object>) beanDefinition.getBeanType();
        Object bean = beanContext.findBean(beanType, qualifier).orElseThrow(() -> new MessageListenerException("Could not find the bean to execute the method " + method));
        DefaultExecutableBinder<PubSubConsumerState> binder = new DefaultExecutableBinder<>();
        if (subscriptionAnnotation != null) {
            String subscriptionName = subscriptionAnnotation.getRequiredValue(String.class);
            ProjectSubscriptionName projectSubscriptionName = PubSubSubscriptionUtils.toProjectSubscriptionName(subscriptionName, googleCloudConfiguration.getProjectId());
            String defaultContentType = subscriptionAnnotation.stringValue("contentType").orElse(MediaType.APPLICATION_JSON);
            String configuration = subscriptionAnnotation.stringValue("configuration").orElse("");
            MessageReceiver receiver = (PubsubMessage message, AckReplyConsumer ackReplyConsumer) -> {
                String messageContentType = message.getAttributesMap().getOrDefault("Content-Type", "");
                String contentType = Optional.of(messageContentType).filter(StringUtils::isNotEmpty).orElse(defaultContentType);
                DefaultPubSubAcknowledgement pubSubAcknowledgement = new DefaultPubSubAcknowledgement(ackReplyConsumer);
                PubSubConsumerState consumerState = new PubSubConsumerState(message, ackReplyConsumer, projectSubscriptionName, contentType);
                try {
                    BoundExecutable executable = null;
                    try {
                        executable = binder.bind(method, binderRegistry, consumerState);
                    } catch (Exception ex) {
                        handleException(new PubSubMessageReceiverException("Error binding message to the method", ex, bean, consumerState));
                    }
                    // Discard result
                    executable.invoke(bean);
                    if (!hasAckArg) {
                        // if manual ack is not specified we auto ack message after method execution
                        pubSubAcknowledgement.ack();
                    } else {
                        Optional<Object> boundAck = Arrays.stream(executable.getBoundArguments()).filter(o -> (o instanceof DefaultPubSubAcknowledgement)).findFirst();
                        if (boundAck.isPresent()) {
                            DefaultPubSubAcknowledgement manualAck = (DefaultPubSubAcknowledgement) boundAck.get();
                            if (!manualAck.isClientAck()) {
                                logger.warn("Method {} was executed and no message acknowledge detected. Did you forget to invoke ack()/nack()?", method.getName());
                            }
                        }
                    }
                } catch (Exception e) {
                    handleException(new PubSubMessageReceiverException("Error handling message", e, bean, consumerState));
                }
            };
            try {
                this.subscriberFactory.createSubscriber(new SubscriberFactoryConfig(projectSubscriptionName, receiver, configuration, pubSubConfigurationProperties.getSubscribingExecutor()));
            } catch (Exception e) {
                throw new PubSubListenerException("Failed to create subscriber", e);
            }
        }
    }
}
Also used : java.util(java.util) Subscription(io.micronaut.gcp.pubsub.annotation.Subscription) BeanContext(io.micronaut.context.BeanContext) MessageListenerException(io.micronaut.messaging.exceptions.MessageListenerException) LoggerFactory(org.slf4j.LoggerFactory) PubSubSubscriptionUtils(io.micronaut.gcp.pubsub.support.PubSubSubscriptionUtils) ExecutableMethod(io.micronaut.inject.ExecutableMethod) AckReplyConsumer(com.google.cloud.pubsub.v1.AckReplyConsumer) PubSubMessageSerDesRegistry(io.micronaut.gcp.pubsub.serdes.PubSubMessageSerDesRegistry) PubsubMessage(com.google.pubsub.v1.PubsubMessage) MediaType(io.micronaut.http.MediaType) PubSubConfigurationProperties(io.micronaut.gcp.pubsub.configuration.PubSubConfigurationProperties) BoundExecutable(io.micronaut.core.bind.BoundExecutable) ConversionService(io.micronaut.core.convert.ConversionService) DefaultExecutableBinder(io.micronaut.core.bind.DefaultExecutableBinder) PubSubListener(io.micronaut.gcp.pubsub.annotation.PubSubListener) MessageReceiver(com.google.cloud.pubsub.v1.MessageReceiver) Logger(org.slf4j.Logger) GoogleCloudConfiguration(io.micronaut.gcp.GoogleCloudConfiguration) PubSubMessageReceiverException(io.micronaut.gcp.pubsub.exception.PubSubMessageReceiverException) Qualifiers(io.micronaut.inject.qualifiers.Qualifiers) Singleton(jakarta.inject.Singleton) Acknowledgement(io.micronaut.messaging.Acknowledgement) ExecutableMethodProcessor(io.micronaut.context.processor.ExecutableMethodProcessor) StringUtils(io.micronaut.core.util.StringUtils) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) ProjectSubscriptionName(com.google.pubsub.v1.ProjectSubscriptionName) BeanDefinition(io.micronaut.inject.BeanDefinition) Qualifier(jakarta.inject.Qualifier) io.micronaut.gcp.pubsub.bind(io.micronaut.gcp.pubsub.bind) PubSubMessageReceiverExceptionHandler(io.micronaut.gcp.pubsub.exception.PubSubMessageReceiverExceptionHandler) PubSubListenerException(io.micronaut.gcp.pubsub.exception.PubSubListenerException) PubsubMessage(com.google.pubsub.v1.PubsubMessage) Acknowledgement(io.micronaut.messaging.Acknowledgement) StringUtils(io.micronaut.core.util.StringUtils) Subscription(io.micronaut.gcp.pubsub.annotation.Subscription) MessageListenerException(io.micronaut.messaging.exceptions.MessageListenerException) AckReplyConsumer(com.google.cloud.pubsub.v1.AckReplyConsumer) ProjectSubscriptionName(com.google.pubsub.v1.ProjectSubscriptionName) PubSubMessageReceiverException(io.micronaut.gcp.pubsub.exception.PubSubMessageReceiverException) DefaultExecutableBinder(io.micronaut.core.bind.DefaultExecutableBinder) MessageListenerException(io.micronaut.messaging.exceptions.MessageListenerException) PubSubMessageReceiverException(io.micronaut.gcp.pubsub.exception.PubSubMessageReceiverException) PubSubListenerException(io.micronaut.gcp.pubsub.exception.PubSubListenerException) MessageReceiver(com.google.cloud.pubsub.v1.MessageReceiver) BoundExecutable(io.micronaut.core.bind.BoundExecutable) PubSubListenerException(io.micronaut.gcp.pubsub.exception.PubSubListenerException)

Example 10 with ExecutableMethod

use of io.micronaut.inject.ExecutableMethod in project micronaut-jms by micronaut-projects.

the class AbstractJMSListenerMethodProcessor method registerListener.

private void registerListener(ExecutableMethod<?, ?> method, String connectionFactoryName, BeanDefinition<?> beanDefinition, AnnotationValue<T> destinationAnnotation, JMSDestinationType type) {
    validateArguments(method);
    final Class<?> targetClass = Stream.of(method.getArguments()).filter(arg -> arg.isDeclaredAnnotationPresent(MessageBody.class) || arg.isDeclaredAnnotationPresent(io.micronaut.jms.annotations.Message.class)).findAny().map(Argument::getClass).get();
    final String destination = destinationAnnotation.getRequiredValue(String.class);
    final int acknowledgeMode = destinationAnnotation.getRequiredValue("acknowledgeMode", Integer.class);
    final boolean transacted = destinationAnnotation.getRequiredValue("transacted", Boolean.class);
    final JMSListenerContainerFactory listenerFactory = beanContext.findBean(JMSListenerContainerFactory.class).orElseThrow(() -> new IllegalStateException("No JMSListenerFactory configured"));
    final JMSConnectionPool connectionPool = beanContext.getBean(JMSConnectionPool.class, Qualifiers.byName(connectionFactoryName));
    final Object bean = beanContext.findBean(beanDefinition.getBeanType()).get();
    final ExecutorService executor = getExecutorService(destinationAnnotation);
    MessageListener listener = generateAndBindListener(bean, method, executor, CLIENT_ACKNOWLEDGE == acknowledgeMode);
    listenerFactory.registerListener(connectionPool, destination, listener, targetClass, transacted, acknowledgeMode, type);
}
Also used : JMSListener(io.micronaut.jms.annotations.JMSListener) BeanContext(io.micronaut.context.BeanContext) JMSConnectionPool(io.micronaut.jms.pool.JMSConnectionPool) LoggerFactory(org.slf4j.LoggerFactory) MessageListener(javax.jms.MessageListener) ExecutableMethod(io.micronaut.inject.ExecutableMethod) JMSDestinationType(io.micronaut.jms.model.JMSDestinationType) JMSListenerContainerFactory(io.micronaut.jms.listener.JMSListenerContainerFactory) Argument(io.micronaut.core.type.Argument) BoundExecutable(io.micronaut.core.bind.BoundExecutable) Message(javax.jms.Message) DefaultExecutableBinder(io.micronaut.core.bind.DefaultExecutableBinder) ExecutorService(java.util.concurrent.ExecutorService) MessageAcknowledgementException(io.micronaut.messaging.exceptions.MessageAcknowledgementException) Logger(org.slf4j.Logger) Qualifiers(io.micronaut.inject.qualifiers.Qualifiers) ExecutableMethodProcessor(io.micronaut.context.processor.ExecutableMethodProcessor) JMSException(javax.jms.JMSException) Assert(io.micronaut.jms.util.Assert) Stream(java.util.stream.Stream) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) Annotation(java.lang.annotation.Annotation) BeanDefinition(io.micronaut.inject.BeanDefinition) JMSArgumentBinderRegistry(io.micronaut.jms.bind.JMSArgumentBinderRegistry) MessageBody(io.micronaut.messaging.annotation.MessageBody) CLIENT_ACKNOWLEDGE(javax.jms.Session.CLIENT_ACKNOWLEDGE) Message(javax.jms.Message) MessageListener(javax.jms.MessageListener) JMSConnectionPool(io.micronaut.jms.pool.JMSConnectionPool) JMSListenerContainerFactory(io.micronaut.jms.listener.JMSListenerContainerFactory) ExecutorService(java.util.concurrent.ExecutorService) MessageBody(io.micronaut.messaging.annotation.MessageBody)

Aggregations

ExecutableMethod (io.micronaut.inject.ExecutableMethod)17 AnnotationValue (io.micronaut.core.annotation.AnnotationValue)11 BeanContext (io.micronaut.context.BeanContext)8 Qualifiers (io.micronaut.inject.qualifiers.Qualifiers)8 ExecutableMethodProcessor (io.micronaut.context.processor.ExecutableMethodProcessor)7 BoundExecutable (io.micronaut.core.bind.BoundExecutable)7 DefaultExecutableBinder (io.micronaut.core.bind.DefaultExecutableBinder)7 BeanDefinition (io.micronaut.inject.BeanDefinition)7 MessageBody (io.micronaut.messaging.annotation.MessageBody)6 Singleton (jakarta.inject.Singleton)6 Logger (org.slf4j.Logger)6 LoggerFactory (org.slf4j.LoggerFactory)6 Argument (io.micronaut.core.type.Argument)5 Map (java.util.Map)5 ExecutorService (java.util.concurrent.ExecutorService)5 InterceptedMethod (io.micronaut.aop.InterceptedMethod)4 StringUtils (io.micronaut.core.util.StringUtils)4 ConsumerAware (io.micronaut.configuration.kafka.ConsumerAware)3 ConsumerRegistry (io.micronaut.configuration.kafka.ConsumerRegistry)3 KafkaAcknowledgement (io.micronaut.configuration.kafka.KafkaAcknowledgement)3