如何使用AWS 2.0 SDK重新处理进行中的SQS消息

时间:2019-02-14 13:37:07

标签: amazon-sqs

我正在用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文档似乎非常分散。

我是否需要建立第二个排队机制来处理这种情况?我是否误读了重试机制的工作原理?

1 个答案:

答案 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等)。这旨在自动处理间歇性节流,联网或服务问题。

处理消息是您自己的逻辑,因此,如果要管理与此相关的任何重试(并确定一次简单的重试即可确定要解决的问题类型),这就是您的工作。