Search in sources :

Example 1 with PubSubListenerException

use of io.micronaut.gcp.pubsub.exception.PubSubListenerException 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 2 with PubSubListenerException

use of io.micronaut.gcp.pubsub.exception.PubSubListenerException in project micronaut-gcp by micronaut-projects.

the class DefaultSubscriberFactory method createSubscriber.

@Override
public Subscriber createSubscriber(SubscriberFactoryConfig config) {
    Subscriber subscriber = subscribers.compute(config.getSubscriptionName(), (k, v) -> {
        if (v == null) {
            Subscriber.Builder builder = Subscriber.newBuilder(config.getSubscriptionName(), config.getReceiver()).setChannelProvider(this.transportChannelProvider).setCredentialsProvider(this.credentialsProvider);
            Optional<SubscriberConfigurationProperties> subscriberConfiguration = beanContext.findBean(SubscriberConfigurationProperties.class, Qualifiers.byName(config.getSubscriberConfiguration()));
            String executor = subscriberConfiguration.map(s -> s.getExecutor()).orElse(config.getDefaultExecutor());
            ExecutorService executorService = beanContext.getBean(ExecutorService.class, Qualifiers.byName(executor));
            if (!(executorService instanceof ScheduledExecutorService)) {
                throw new IllegalStateException("Invalid Executor type provided, please make sure you have a ScheduledExecutorService configured for Subscriber: " + config.getSubscriptionName().getSubscription());
            }
            builder.setExecutorProvider(FixedExecutorProvider.create((ScheduledExecutorService) executorService));
            if (subscriberConfiguration.isPresent()) {
                SubscriberConfigurationProperties properties = subscriberConfiguration.get();
                builder.setMaxAckExtensionPeriod(properties.getMaxAckExtensionPeriod());
                builder.setParallelPullCount(properties.getParallelPullCount());
                builder.setMaxDurationPerAckExtension(properties.getMaxDurationPerAckExtension());
                builder.setFlowControlSettings(properties.getFlowControlSettings().build());
            }
            return builder.build();
        }
        throw new PubSubListenerException(String.format("Subscription %s is already registered for another" + " method", config.getSubscriptionName().toString()));
    });
    subscriber.startAsync();
    return subscriber;
}
Also used : Logger(org.slf4j.Logger) Iterator(java.util.Iterator) BeanContext(io.micronaut.context.BeanContext) SubscriberConfigurationProperties(io.micronaut.gcp.pubsub.configuration.SubscriberConfigurationProperties) LoggerFactory(org.slf4j.LoggerFactory) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Qualifiers(io.micronaut.inject.qualifiers.Qualifiers) Singleton(jakarta.inject.Singleton) Subscriber(com.google.cloud.pubsub.v1.Subscriber) PreDestroy(javax.annotation.PreDestroy) SubscriberInterface(com.google.cloud.pubsub.v1.SubscriberInterface) Modules(io.micronaut.gcp.Modules) TransportChannelProvider(com.google.api.gax.rpc.TransportChannelProvider) Map(java.util.Map) CredentialsProvider(com.google.api.gax.core.CredentialsProvider) FixedExecutorProvider(com.google.api.gax.core.FixedExecutorProvider) ProjectSubscriptionName(com.google.pubsub.v1.ProjectSubscriptionName) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) Optional(java.util.Optional) PubSubListenerException(io.micronaut.gcp.pubsub.exception.PubSubListenerException) ExecutorService(java.util.concurrent.ExecutorService) Named(jakarta.inject.Named) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) Subscriber(com.google.cloud.pubsub.v1.Subscriber) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) ExecutorService(java.util.concurrent.ExecutorService) SubscriberConfigurationProperties(io.micronaut.gcp.pubsub.configuration.SubscriberConfigurationProperties) PubSubListenerException(io.micronaut.gcp.pubsub.exception.PubSubListenerException)

Example 3 with PubSubListenerException

use of io.micronaut.gcp.pubsub.exception.PubSubListenerException in project micronaut-gcp by micronaut-projects.

the class PubSubBodyBinder method bind.

@Override
public BindingResult<Object> bind(ArgumentConversionContext<Object> context, PubSubConsumerState state) {
    Argument<Object> bodyType = context.getArgument();
    Object result = null;
    if (bodyType.getType().equals(byte[].class)) {
        result = state.getPubsubMessage().getData().toByteArray();
    } else if (bodyType.getType().equals(PubsubMessage.class)) {
        result = state.getPubsubMessage();
    } else {
        if (StringUtils.isEmpty(state.getContentType()) && !state.getPubsubMessage().containsAttributes("Content-Type")) {
            throw new PubSubListenerException("Could not detect Content-Type header at message and no Content-Type specified on method.");
        }
        PubSubMessageSerDes serDes = serDesRegistry.find(state.getContentType()).orElseThrow(() -> new PubSubListenerException("Could not locate a valid SerDes implementation for type: " + state.getContentType()));
        result = serDes.deserialize(state.getPubsubMessage().getData().toByteArray(), bodyType);
    }
    Object finalResult = result;
    return () -> Optional.ofNullable(finalResult);
}
Also used : PubSubMessageSerDes(io.micronaut.gcp.pubsub.serdes.PubSubMessageSerDes) PubSubListenerException(io.micronaut.gcp.pubsub.exception.PubSubListenerException) PubsubMessage(com.google.pubsub.v1.PubsubMessage)

Aggregations

PubSubListenerException (io.micronaut.gcp.pubsub.exception.PubSubListenerException)3 ProjectSubscriptionName (com.google.pubsub.v1.ProjectSubscriptionName)2 PubsubMessage (com.google.pubsub.v1.PubsubMessage)2 BeanContext (io.micronaut.context.BeanContext)2 Qualifiers (io.micronaut.inject.qualifiers.Qualifiers)2 Singleton (jakarta.inject.Singleton)2 Logger (org.slf4j.Logger)2 LoggerFactory (org.slf4j.LoggerFactory)2 CredentialsProvider (com.google.api.gax.core.CredentialsProvider)1 FixedExecutorProvider (com.google.api.gax.core.FixedExecutorProvider)1 TransportChannelProvider (com.google.api.gax.rpc.TransportChannelProvider)1 AckReplyConsumer (com.google.cloud.pubsub.v1.AckReplyConsumer)1 MessageReceiver (com.google.cloud.pubsub.v1.MessageReceiver)1 Subscriber (com.google.cloud.pubsub.v1.Subscriber)1 SubscriberInterface (com.google.cloud.pubsub.v1.SubscriberInterface)1 ExecutableMethodProcessor (io.micronaut.context.processor.ExecutableMethodProcessor)1 AnnotationValue (io.micronaut.core.annotation.AnnotationValue)1 BoundExecutable (io.micronaut.core.bind.BoundExecutable)1 DefaultExecutableBinder (io.micronaut.core.bind.DefaultExecutableBinder)1 ConversionService (io.micronaut.core.convert.ConversionService)1