我正在用SQS处理器替换JMS处理器。收到消息后,我需要对多个第三方系统进行更新调用。我不确定如何成功检索SQS消息,但是处理一个或多个调用以更新第三方系统失败。在JMS世界中,我们将引发异常,并且它将以递减的增量重新发送相同的JMS消息,然后在4次重试后最终进入DLQ。这是我到目前为止的代码。
我有以下帮助方法来巩固邮件检索
public static List<Message> receiveMessage(SqsClient sqs, String queueUrl) throws AwsException {
try {
ReceiveMessageRequest req = ReceiveMessageRequest.builder()
.queueUrl(queueUrl)
.waitTimeSeconds(LONG_POLL_DURATION)
.build();
ReceiveMessageResponse resp = sqs.receiveMessage(req);
if (resp != null) {
if (!Collections.isNullOrEmpty(resp.messages())) {
return resp.messages();
} else {
return new ArrayList<>();
}
} else {
return new ArrayList<>();
}
} catch (SdkException e) {
throw new AwsException("An error occurred receiving SQS message: " + e.getMessage(), e);
}
}
我的用于处理SQS消息的代码
try (SqsClient client = SqsUtil.getClient()) {
while(!shutdown) {
List<Message> messages = SqsUtil.receiveMessage(client, queueUrl);
if (!messages.isEmpty()) {
for(Message msg : messages) {
boolean errorOccurred = false;
try {
//Convert SQS message to System 1 Request
System1Request req1 = convert(msg);
system1Client.process(req1);
} catch (System1Exception e) {
//log error
errorOccurred = true;
}
try {
//Convert SQS message to System 2 Request
System2Request req2 = convert(msg);
system2Client.process(req2);
} catch (System1Exception e) {
//log error
errorOccurred = true;
}
if (!errorOccurred) {
//delete SQS message
} else {
//TODO: how do I re-process the message using SQS
}
}
}
}
}
根据我的理解,SQS客户端具有JDK内置的重试功能,但我不认为这适用于运行中的消息吗?我在API中看不到如何将消息重新添加到SQS队列中。我很犹豫将重试逻辑构建到我的应用程序中,以防Pod重新启动并且消息丢失。
我知道,如果不删除该消息,则最终将其传输到DLQ,但是在将消息发送到DLQ之前,我想尝试几次重试。 SQS Example code没有显示如何处理,并且AWS文档似乎非常分散。
我是否需要建立第二个排队机制来处理这种情况?我是否误读了重试机制的工作原理?
答案 0 :(得分:1)
我认为您缺少的关键概念是SQS visibility timeout
当使用者从队列接收并处理消息时,该消息将保留在队列中。 Amazon SQS不会自动删除消息。由于Amazon SQS是分布式系统,因此无法保证使用者实际上收到了消息(例如,由于连接问题或使用者应用程序中的问题)。因此,消费者必须在接收和处理消息后从队列中删除该消息。
可见性超时(可在设置中配置)可以防止多个使用者一次尝试处理同一条消息(请记住,它尚未真正从队列中删除),同时可以确保您不会 丢失消息。
如果未删除消息,则可见性超时最终将到期,并且SQS可以在以后的receiveMessage
调用中再次返回它(重新驱动消息)。如果这种情况发生的次数过多(通常是在消息处理过程中发生未捕获的异常或某些异常),则SQS会将消息传递到SQS Dead-Letter-Queue (DLQ)(如果已配置)。
记住-这里的关键循环本质上是:
while (keepProcessing()) {
Message m = receiveMessage(); // call SQS to get message
processMessage(m); // your own logic to process
deleteMessage(m); // call SQS to ACK the message
}
...如果在其中某处引发异常,则该消息不会丢失-它会被重新驱动(基于DLQ策略和visibleTimeout)
The AWS SDK built-in retry capabilities(不同于重新发送消息)用于对SDK的调用(即:receiveMessage,deleteMessage等)。这旨在自动处理间歇性节流,联网或服务问题。
处理消息是您自己的逻辑,因此,如果要管理与此相关的任何重试(并确定一次简单的重试即可确定要解决的问题类型),这就是您的工作。