Java Spring Cloud SQS消费阻塞,直到处理完所有消息
我们正在使用它与SQS进行交互。我们使用Java Spring Cloud SQS消费阻塞,直到处理完所有消息,java,spring,spring-boot,spring-cloud,amazon-sqs,Java,Spring,Spring Boot,Spring Cloud,Amazon Sqs,我们正在使用它与SQS进行交互。我们使用@SqsListener注释从队列中提取消息。我们有deletionPolicy=NEVER,这意味着我们手动确认所收到的所有消息 我们的问题是,SimpleMessageListenerContainer(处理队列中消息的处理)等待所有工作线程完成,然后再从队列中提取更多消息 换句话说,我们看到的是: 从队列中提取10条消息 启动10个线程进行工作 执行工作的线程之一在缓慢的IO调用中被阻塞 应用程序现在被阻止从队列中获取更多消息,因此在缓慢的调用完成
@SqsListener
注释从队列中提取消息。我们有deletionPolicy=NEVER
,这意味着我们手动确认所收到的所有消息
我们的问题是,SimpleMessageListenerContainer
(处理队列中消息的处理)等待所有工作线程完成,然后再从队列中提取更多消息
换句话说,我们看到的是:
- 从队列中提取10条消息
- 启动10个线程进行工作
- 执行工作的线程之一在缓慢的IO调用中被阻塞
- 应用程序现在被阻止从队列中获取更多消息,因此在缓慢的调用完成之前,它根本无法做更多的工作
SimpleMessageListener.AsynchronousMessageListener
中看到负责此操作的代码
@Override
public void run() {
while (isQueueRunning()) {
try {
ReceiveMessageResult receiveMessageResult = getAmazonSqs().receiveMessage(this.queueAttributes.getReceiveMessageRequest());
CountDownLatch messageBatchLatch = new CountDownLatch(receiveMessageResult.getMessages().size());
for (Message message : receiveMessageResult.getMessages()) {
if (isQueueRunning()) {
MessageExecutor messageExecutor = new MessageExecutor(this.logicalQueueName, message, this.queueAttributes);
getTaskExecutor().execute(new SignalExecutingRunnable(messageBatchLatch, messageExecutor));
} else {
messageBatchLatch.countDown();
}
}
try {
messageBatchLatch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
} catch (Exception e) {
getLogger().warn("An Exception occurred while polling queue '{}'. The failing operation will be " +
"retried in {} milliseconds", this.logicalQueueName, getBackOffTime(), e);
try {
//noinspection BusyWait
Thread.sleep(getBackOffTime());
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
}
理想情况下,我们希望消息侦听器不断地从队列中挑选消息进行处理
我们似乎无法实现自己的MessageListenerContainer
,因为AbstractMessageListenerContainer
是本地包
有什么方法可以避免这种行为吗?保持消息轮询线程的是
messageBatchLatch.await()
语句。看来只要拆下门闩就行了。比如:
@Override
public void run() {
while (isQueueRunning()) {
try {
ReceiveMessageResult receiveMessageResult = getAmazonSqs().receiveMessage(this.queueAttributes.getReceiveMessageRequest());
for (Message message : receiveMessageResult.getMessages()) {
if (isQueueRunning()) {
MessageExecutor messageExecutor = new MessageExecutor(this.logicalQueueName, message, this.queueAttributes);
getTaskExecutor().execute(new SignalExecutingRunnable(messageExecutor));
}
}
} catch (Exception e) {
getLogger().warn("An Exception occurred while polling queue '{}'. The failing operation will be " +
"retried in {} milliseconds", this.logicalQueueName, getBackOffTime(), e);
try {
//noinspection BusyWait
Thread.sleep(getBackOffTime());
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
}
如果您的TaskExecutor
实现:
-具有固定大小的线程池
-调用execute
函数且没有可用线程时阻塞
这是大多数实现的工作方式,但值得检查您的实现。谢谢,但我们如何真正覆盖
AsynchronousMessageListener
?它是私有的..抱歉,我没有意识到这不是您的代码:-(…好吧,在这种情况下,假设spring不允许您重写该行为,我想实现您自己的队列轮询代码会更容易…您可以重写startQueue(String queueName,QueueAttributes QueueAttributes)
,对吗?