spring-attic/spring-cloud-aws

Prevent spring-cloud-aws-messaging from trying to stop the queue

kkaushik90f opened this issue ยท 10 comments

I'm using spring-cloud-aws-messaging in a Spring Boot 2.1.9.RELEASE project.
I have SQS queue created manually in AWS.

It is being used like:

@SqsListener("${sqs.name.incoming}")
public void listen(String message) {
    ...
}

It works fine. But when I stop my application in IDE, or when the Spring Boot tests finish, it tries to stop the queue. It can't stop it and eventually times out. It throws this exception:

2019-10-29 15:40:07.949  WARN 10378 --- [       Thread-2] s.c.a.m.l.SimpleMessageListenerContainer : An exception occurred while stopping queue 'my-awesome-queue-name'

java.util.concurrent.TimeoutException: null
    at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:204) ~[na:na]
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer.waitForRunningQueuesToStop(SimpleMessageListenerContainer.java:161) ~[spring-cloud-aws-messaging-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer.doStop(SimpleMessageListenerContainer.java:140) ~[spring-cloud-aws-messaging-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.AbstractMessageListenerContainer.stop(AbstractMessageListenerContainer.java:351) ~[spring-cloud-aws-messaging-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer.stop(SimpleMessageListenerContainer.java:45) ~[spring-cloud-aws-messaging-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.AbstractMessageListenerContainer.stop(AbstractMessageListenerContainer.java:239) ~[spring-cloud-aws-messaging-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer.stop(SimpleMessageListenerContainer.java:45) ~[spring-cloud-aws-messaging-2.1.3.RELEASE.jar:2.1.3.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor.doStop(DefaultLifecycleProcessor.java:238) ~[spring-context-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor.access$300(DefaultLifecycleProcessor.java:53) ~[spring-context-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.stop(DefaultLifecycleProcessor.java:377) ~[spring-context-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor.stopBeans(DefaultLifecycleProcessor.java:210) ~[spring-context-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor.onClose(DefaultLifecycleProcessor.java:128) ~[spring-context-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1018) ~[spring-context-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext$1.run(AbstractApplicationContext.java:945) ~[spring-context-5.1.10.RELEASE.jar:5.1.10.RELEASE]

This waiting slows down application or tests shutdown.

How do I tell spring-cloud-aws-messaging that it is a manually created queue and it should not try to shut it down?
Not getting an answer on stackoverflow.

dmile commented

Actually, it's not about queues. I agree, it's not clear from their names, but methods like notifyRunningQueuesToStop, waitForRunningQueuesToStop or stopQueue are working with message listeners. When we have the TimeoutException we are waiting for AsynchronousMessageListener.
The listener can be busy with long polling connection up to 20 seconds. But default timeout of waiting is only 10 seconds.

This waiting slows down application or tests shutdown.

For testing scenario / faster shutdown we can reduce timeout for poll requests

@Bean
public SimpleMessageListenerContainerFactory simpleMessageListenerContainerFactory(
    AmazonSQSAsync amazonSQSAsync
) {
  SimpleMessageListenerContainerFactory factory = new SimpleMessageListenerContainerFactory();
  factory.setAmazonSqs(amazonSQSAsync);
  factory.setWaitTimeOut(1); // less than 10 sec
  return factory;
}

Thanks @dmile. As mentioned here, long polling helps reduce cost. So I'll leave it as it is in production, but will override that bean for tests as you suggested.

Would it be possible to set the timeout for the shutdown of the thread pool to the same value as the timeout for the long poll by default? I guess the default timeout of 20s for the long poll is something that is defined by the aws client. But if the developer provides a value for the long poll timeout to Spring, Spring could also apply it to the timeout for the shutdown of the threadpool.

waitTimeOut should be configurable via properties so that it's easier to provide profile-specific configuration.

@maciejwalkowiak waitTimeOut is configurable in the SimpleMessageListenerContainerFactory.

But we need queueStopTimeout to be exposed as well - or have the mechanism that it uses the waitTimeout.

I need some time to dig through SQS related issues. You are welcome to contribute PR but I'm not able at this point to guide you.

@huehnerlady @maciejwalkowiak any progress?

Happy to create a PR that exposes the queueStopTimeout in the SimpleMessageListenerContainerFactory and let one configure this property.

@maciejwalkowiak thank you so much for implementing this. Do you have any idea when it will be released? :)

Kudos go to @mkatircioglu! I am sorry but I can't tell exactly when 2.3 will be released as it's going to be first release after Spring Cloud AWS leaves Spring Cloud release train.

@maciejwalkowiak do you have an update for this? any timeline when 2.3 will be released? or could it maybe be relesed in an earlier version after all?