SpringBoot @SqsListener-不起作用-带有异常-TaskRejectedException

时间:2018-07-17 04:04:55

标签: java spring-boot spring-cloud amazon-sqs

我有一个AWS SQS,队列中已经有5000条消息(示例消息看起来像这样的“ Hello @ 1”) 我创建了一个SpringBoot应用程序,并在一个组件类中创建了一种从SQS读取消息的方法。

package com.example.aws.sqs.service;

import org.springframework.cloud.aws.messaging.listener.SqsMessageDeletionPolicy;
import org.springframework.cloud.aws.messaging.listener.annotation.SqsListener;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class MessageReceiverService {   

@SqsListener(value = { "${cloud.aws.sqs.url}" }, deletionPolicy = SqsMessageDeletionPolicy.ALWAYS)
public void readMessage(String message){
    log.info("Reading Message... {}", message);
}

}

我的主要SpringBoot类

@SpringBootApplication 
public class AwsSqsApplicationConsumer {
public static void main(String[] args) {
    SpringApplication.run(AwsSqsApplicationConsumer.class, args);
}
}

应用程序运行时出现异常:

s.c.a.m.l.SimpleMessageListenerContainer : An Exception occurred while polling queue '<my sqs name>'. The failing operation will be retried in 10000 milliseconds
org.springframework.core.task.TaskRejectedException: Executor [java.util.concurrent.ThreadPoolExecutor@7c1594a5[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 20]] did not accept task: org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$SignalExecutingRunnable@1cbd9ef2
at org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.execute(ThreadPoolTaskExecutor.java:309) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$AsynchronousMessageListener.run(SimpleMessageListenerContainer.java:286) ~[spring-cloud-aws-messaging-2.0.0.RELEASE.jar:2.0.0.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_65]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_65]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_65]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_65]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_65]
Caused by: java.util.concurrent.RejectedExecutionException: Task org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$SignalExecutingRunnable@1cbd9ef2 rejected from java.util.concurrent.ThreadPoolExecutor@7c1594a5[Running, pool size = 3, active threads = 2, queued tasks = 0, completed tasks = 20]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047) ~[na:1.8.0_65]
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823) [na:1.8.0_65]
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369) [na:1.8.0_65]
at org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.execute(ThreadPoolTaskExecutor.java:306) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
... 6 common frames omitted

我没有配置任何自定义执行器服务。使用预配置的Spring Bean。 springBootVersion ='2.0.3.RELEASE' springCloudVersion ='Finchley.RELEASE'

6 个答案:

答案 0 :(得分:5)

设置最大邮件数似乎可以解决此问题:

@Bean
public SimpleMessageListenerContainerFactory simpleMessageListenerContainerFactory(AmazonSQSAsync amazonSQS){
    SimpleMessageListenerContainerFactory factory = new SimpleMessageListenerContainerFactory();
    factory.setAmazonSqs(amazonSQS);
    factory.setMaxNumberOfMessages(10);
    return factory;
}

答案 1 :(得分:4)

我认为这是Spring中的错误或疏忽。问题源于默认值:

public class SimpleMessageListenerContainer extends AbstractMessageListenerContainer {

    private static final int DEFAULT_WORKER_THREADS = 2;

abstract class AbstractMessageListenerContainer implements InitializingBean, DisposableBean, SmartLifecycle, BeanNameAware {
    private static final int DEFAULT_MAX_NUMBER_OF_MESSAGES = 10;

如果未设置maxNumberOfMessages,则它将使用10作为从SQS提取的消息数,使用2作为任务执行程序中的工作程序数。这意味着,如果它一次提取3条或更多条消息,则会出现该异常。如果您将maxNumberOfMessages手动设置为一个值(任何值),它将在两个地方都使用该同步值,正如我所期望的那样:

    @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(
            SimpleMessageListenerContainerFactory factory, QueueMessageHandler messageHandler)
    {
        SimpleMessageListenerContainer container = factory.createSimpleMessageListenerContainer();
        container.setMaxNumberOfMessages(5);
        container.setMessageHandler(messageHandler);
        return container;
    }

答案 2 :(得分:2)

问题在于侦听器线程配置。请参阅以下

...
ThreadPoolExecutor@7c1594a5[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 20]]
...

默认线程池大小小于您想要的大小。

将以下配置添加到您的Spring应用程序

@Configuration
public class TasksConfiguration implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(5); // TODO: Load this from configuration
        taskScheduler.initialize();
        taskRegistrar.setTaskScheduler(taskScheduler);
    }
}

现在,您应该能够处理这些任务了。

P.S。无论早先拒绝了什么任务,它们都会在特定时间段后被提起。

编辑:我认为人们对.setPoolSize(5000)行中的数字感到恐惧。这是一个可配置的号码,您可以选择适合您要求的任何号码。对于答案,我将其减少为一个较小的数字。

答案 3 :(得分:1)

嘿,我使用Spring Listener解决了这个问题。以下是代码,希望对您有所帮助。

在以下解决方案中,所有bean初始化完成后,将分配一个具有更大池大小的新任务执行程序。

if (!((AndroidDriver)driver).findElementsByAndroidUIAutomator("UiSelector().textContains(\"" + coverage + "\")").isEmpty()) {
 //some logic when element is located
} else {
 //scroll to the particular element
}

答案 4 :(得分:0)

在 MessageRecieverService 上添加 @EnableSqs 注解

答案 5 :(得分:-1)

无法在前面的答案中添加注释,以进一步说明问题发生的原因以及消息设置MaxNumberOfMessages的解决方案为何起作用。希望以下内容有助于弄清一切。

SimpleMessageListenerContainer的{​​{1}}配置为核心池大小为2个线程,最大池大小为3个线程,队列容量为0。但是,默认的最大消息数为将对Amazon SQS的轮询的返回值设置为10。这意味着,如果一次轮询中有10条消息可用,则将没有足够的线程来处理它们。这样就抛出了ThreadPoolTaskExecutor

RejectedExecutionException上将setMaxNumberOfMessages配置为10会将最大线程池大小设置为11,这将允许有足够的线程可用。它没有设置队列容量。

要设置队列容量,可以初始化一个单独的TaskExecutor并在SimpleMessageListenerContainerFactory bean上进行设置,如下所示:

SimpleMessageListenerContainerFactory

我使用的值是coreThreadCount = 5,maxThreadCount = 20,queueCapacity = 10。

正如我已经说过的,我认为在SimpleMessageListenerContainerFactory上将setMaxNumberOfMessages配置为10应该足以处理从单个请求中提取的所有批处理消息。但是,如果您觉得需要对TaskExecutor进行更精确的控制,则此配置也可以正常工作。