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);
}
}
}
}
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;
}
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);
}
Aggregations