Description
Type: Bug
Component:
Describe the bug
The new addition of acknowledgementMode in @SqsListener
is great, but it fails on startup if there are any usage of MessageListenerContainerFactory beans in the app. For example, I may be listening to two different queues. One using MessageListenerContainerFactory
via the factory
annotation param, and another queue using acknowledgementMode
annotation param.
The failure exception is
java.lang.IllegalArgumentException: No MessageListenerContainerFactory bean with name defaultSqsListenerContainerFactory found for endpoint names [test-queue]
at org.springframework.util.Assert.isTrue(Assert.java:129)
at io.awspring.cloud.sqs.config.EndpointRegistrar.createContainerFor(EndpointRegistrar.java:223)
at io.awspring.cloud.sqs.config.EndpointRegistrar.process(EndpointRegistrar.java:218)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at io.awspring.cloud.sqs.config.EndpointRegistrar.afterSingletonsInstantiated(EndpointRegistrar.java:213)
at io.awspring.cloud.sqs.annotation.AbstractListenerAnnotationBeanPostProcessor.afterSingletonsInstantiated(AbstractListenerAnnotationBeanPostProcessor.java:256)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:984)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:323)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331)
This is because SqsAutoConfiguration
has a @CondituionalOnMissingBean
, so it is never created if the same bean type exists in the app.
@ConditionalOnMissingBean
@Bean
public SqsMessageListenerContainerFactory<Object> defaultSqsListenerContainerFactory(...)
Perhaps this can be conditional on a named bean instead to allow both to exist in an app?
Sample
The following example can reproduce the issue.
@Configuration
public class MyAppConfig {
@ConditionalOnMissingBean(name = "ACK_ON_SUCCESS_FACTORY_BEAN_NAME")
@Bean(name = "ACK_ON_SUCCESS_FACTORY_BEAN_NAME")
SqsMessageListenerContainerFactory<Object> acknowledgeOnSuccessFactory(SqsAsyncClient sqsAsyncClient) {
return SqsMessageListenerContainerFactory.builder()
.configure(options -> options.acknowledgementMode(AcknowledgementMode.ALWAYS))
.sqsAsyncClient(sqsAsyncClient)
.build();
}
}
@Component
public class SqsConsumers {
@SqsListener(value = "test-queue-2", factory = "ACK_ON_SUCCESS_FACTORY_BEAN_NAME")
public void consumeSqsQueue2(String message) {
}
@SqsListener(value = "test-queue", acknowledgementMode = SqsListenerAcknowledgementMode.ON_SUCCESS)
public void consumeSqsQueue(String message) {
}
}