在 Java 代码抛出 runtimeException 的情况下,Lambda 函数不会重试 sqs 消息处理

Lambda function does not retry the sqs message processing in case the Java code throws a runtimeException

我有一个用 java 编写的 lambda 函数,它侦听 sqs 事件并尝试对这些 sqs 消息进行某种处理。

根据 lambda 文档,如果 lambda 代码抛出 runtimeException,lambda 会在将同一消息发送回队列之前重试两次。但是,我没有看到这种行为。 我只看到它只处理一次消息。

这是本例中相关 lambda 代码的片段。

@Override
    public Boolean handleRequest(SQSEvent sqsEvent, Context context) {

          try{
               ........some queue message processing.....
          }
          catch(Exception ex){
               throw new RuntimeException("exception occurred");
          }

}

这是否不足以让 lambda 重试消息 2 次?我确实检查了 cloudwatch 以查看 lambda 日志,它只有第一次处理的日志,而不是重试的日志。

谁能告诉我我错过了什么,因为它没有按预期工作。

documentation 表示如果调用是 异步 ,它会再重试两次。 SQS 是一个基于轮询的系统。 Lambda 将轮询队列,并且其所有调用都将是 同步

For poll-based AWS services (Amazon Kinesis, Amazon DynamoDB, Amazon Simple Queue Service), AWS Lambda polls the stream or message queue and invokes your Lambda function synchronously.

您可以做的是在您的源 SQS 队列上配置一个 DLQ,以防您的消息失败,以便您可以进一步分析它或根据您配置的逻辑再次处理消息。

编辑

OP 不知何故无法看到 DLQ 中的消息。我附上了图片以证明它有效。

Lambda sqs-test 由 SQS 队列 sqs-test 中的新消息触发

这些是队列(sqs-test-dlq 配置为 sqs-test 的 DLQ)。

这是 Lambda 函数的代码:

这是sqs-test的配置

这是重新驱动政策

消息在 Lambda 函数中失败后,成功发送到配置的 DLQ:

您一定缺少一些基本配置,因为它可以如上图所示无缝运行。

您在 handleRequest 中缺少 throws 子句。如果你没有那个,那么 lambda 只会吞下异常

public Boolean handleRequest(SQSEvent sqsEvent, Context context) throws RuntimeException

除此之外,Thales Munussi 所说的同步轮询是完全正确的。当您将 sqs 与 lambda 挂钩时,lambda 会轮询 sqs,这会在两者之间保持开放连接,从而使其成为同步连接 根据 aws 文档,lambda 在这种同步情况下不会重试。设置一个 dlq 并在 sqs 本身退休是你最好的办法

请记住,在您的 java 代码中抛出运行时异常后,lambda 会将消息发送回队列 根据您的 sqs 中的 redrive 设置,sqs 将根据 redrive 编号生成相同的事件。

一旦 lambda 未能成功处理 redrive 次数,消息将从主队列发送到 DLQ