【问题标题】:AWS Lambda - How to stop retries when there is a failureAWS Lambda - 出现故障时如何停止重试
【发布时间】:2018-08-10 16:22:39
【问题描述】:

我知道当 Lambda 函数失败时(例如超时),它会尝试再次运行该函数 3 次。有什么办法可以避免这种行为?我一直在阅读文档,但没有发现任何相关信息。

谢谢!

【问题讨论】:

  • 不要将任何故障暴露给 Lambda(自己处理)并且不要超时(您可以从上下文对象中获取剩余时间)。
  • 您可以在 Python 中执行此操作。 boto3 提供了一种对 boto3 客户端进行高级配置的方法。请参考此链接:botocore.readthedocs.io/en/latest/reference/config.html。您可以像这样将重试次数设置为 0:client = boto3.client('ec2', config=Config(retries=dict(max_attempts=0)))
  • @krishna_mee2004 您的解决方案无法解决此问题。 "'max_attempts' -- 一个整数,表示将在单个请求上进行的最大重试尝试次数" 这仅适用于 lambda 客户端

标签: amazon-web-services aws-lambda


【解决方案1】:

当它是 未处理的失败(您没有捕获的错误)或您处理了它但仍然告诉 Lambda 重试时(例如,在 Node 中,当您调用 callback()带有非空的第一个参数)。

要阻止它重试,您应该确保所有错误都得到处理,并通过返回非错误告诉 Lambda 您的调用成功完成(或在 Node 中,调用 callback(null, <any>)

为此,您可以使用 try-catch 将处理函数的整个主体括起来。

module.exports.handler(event, context, callback) {
  try {
    // Do you what you want to do.
    return callback(null, 'Success')
  } catch (err) {
    // You probably still want to log it.
    console.error(err)
    // Return happy despite all the hardships you went through.
    return callback(null, 'Still success')
  }
}

至于由于超时导致的失败,您可以做一些事情。

如果它在您的处理程序外部超时,您的代码通常有问题(例如不正确的数据库配置等),您应该查看。

如果它在调用期间 inside 您的处理程序超时,您可以采取一些措施。

  • 如果是 HTTP 请求,您应该将请求的超时时间设置为比您的 Lambda 的超时时间短,这样它会正确失败并且您可以捕获它。
  • 如果是数据库连接,您可以使用您正在使用的库设置超时。
  • 如果是您的逻辑超时,您可以升级 Lambda 以使用更高的内存 CPU 以使其更快。您也可以查看context.getRemainingTimeInMillis(),了解 Lambda 是否即将超时,以便提前处理。

【讨论】:

  • 感谢您回答@dashmug!如果出现超时错误,它是否也被 try catch 捕获了?因为这是 AWS lamda 的限制。谢谢!
  • 很遗憾,这个 try-catch 无法捕获超时错误。
  • @dashmug try-catch 中的代码执行速度慢了约 5 倍 (js)。 AWS 还有更多的钱))
  • 这样做会阻止您将CloudWatch Metric 用于AWS/Lambda Errors。如果你没问题,那就去吧。
【解决方案2】:

已编辑:现在可以更改 lambda 设置以禁用重试(请参阅 announcement


原答案

无法禁用 Lambda 函数的重试行为。 我建议有两种选择来解决这个问题:

  1. 使您的 Lambda 能够正确处理重试案例。您可以使用重试 Lambda 时相同的 context.AwsRequestId(或相应字段)。
  2. 将您的 Lambda 放入状态机(使用 AWS Step Functions)。您只能禁用重试。 This blog post我写了一个更笼统的解释。

【讨论】:

  • AWS 没有改变这种行为的逻辑是什么?除了赚外快。大声笑
  • 其他选项会将 requestid 推送到 dynamodb,然后检查它是重试还是新调用。再次为 AWS 提供更多资金。大声笑
  • 如果从 StepFucntions 调用 Lambda,如何禁用重试?我有一个重试的 Lambda 步骤。
【解决方案3】:

如果异步调用函数,在ConsoleFunction configuration下,可以修改Retry attempts

【讨论】:

    【解决方案4】:

    由于November 2019,可以将重试次数设置为0。

    这意味着 lambda 不会在出错时重试。

    【讨论】:

      【解决方案5】:

      如前所述,此功能是最近添加的。要使用cloudformation 实现此行为,您将需要AWS::Lambda::VersionAWS::Lambda::EventInvokeConfig

        MyLambda:
          Type: AWS::Serverless::Function
          Properties:
            FunctionName: my-lambda-dev
            ...
      
        MyLambdaVersion:
          Type: AWS::Lambda::Version
          Properties:
            FunctionName: !Ref MyLambda
      
        MyLambdaAsyncConfig:
          Type: AWS::Lambda::EventInvokeConfig
          Properties:
            FunctionName: !Ref MyLambda
            MaximumRetryAttempts: 0
            Qualifier: !GetAtt MyLambdaVersion.Version
      

      【讨论】:

        【解决方案6】:

        如果你使用 Python,我建议你关注this thread

        如果您使用的是 Java,请在 handleRequest 方法中添加以下行:

        ClientConfiguration config = new ClientConfiguration();
        config.setMaxErrorRetry(0);
        

        【讨论】:

          【解决方案7】:

          如果使用 python 则需要将代码放入 try/catch 块中,但是不会有回调。例如:

          try:
              do_something()
          except Exception as e:
              print('Error: ' + str(e))
          

          由于错误已被处理,Lambda 不会重试。

          【讨论】:

            【解决方案8】:

            使用下面的代码来识别并在失败时停止重试。

              exports.handler = (event, context, callback) => {
                  context.callbackWaitsForEmptyEventLoop = false;
                  let lastReqId;
                  if (lastReqId == context.awsRequestId) {
                    console.log("Lambda auto retry detected. Aborting");// you can write your own logic to decide what to do with the failure data
                    return context.succeed();
                  } else {
                    console.log("new context");
                    lastReqId = context.awsRequestId;
                  }
                };
            

            你可以阅读更多关于它here

            【讨论】:

            • 是否保证重试将命中与先前失败的调用相同的容器?因为,如果不是这样,这个逻辑就注定要失败……将请求 ID 推送到外部存储(例如 DynamoDB)会更安全。
            • 其实这绝对肯定会失败。 Lambda 可能会重试多次,每次重试之间都有一段时间。同时,Lambda 很可能被另一个请求调用,更新 lastReqId。当重试进来的时候,你就识别不出来了。
            • 我在流上尝试了一个 poc,这很有效,根据我的分析,如果你正在处理它的流并且 lambda 失败,它将重试失败的请求并且不会再接受另一个请求。但是我看到你有一个有效的观点,因为在其他情况下上述可能会失败
            • context.succeed() 放在catch 块中不是一个选项吗?
            【解决方案9】:

            我通过放置以下代码行实现了这一点:

            callback(null, "message");

            进入我的函数,例如下面对 DynamoDB 的更新。当出现错误时,而不是连续重试几个小时,if / else 之外的这个回调将停止重试。

            dynamodb.updateItem(params, function(err, data){
                             if (err) {
                                console.log(err)
                                callback(err, data)
                        } else {
                             console.log(data);
                             callback(null, data);
                       }
                       callback(null, "message");
                    });
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2023-01-09
              • 1970-01-01
              • 2021-04-09
              • 1970-01-01
              • 2016-08-30
              • 2022-07-08
              • 2021-06-13
              • 1970-01-01
              相关资源
              最近更新 更多