简体   繁体   English

AWS Lambda - 如何在出现故障时停止重试

[英]AWS Lambda - How to stop retries when there is a failure

I know that when a Lambda function fails (for example when there is a time out), it tries to run the function 3 more times again.我知道当 Lambda 函数失败时(例如超时),它会尝试再次运行该函数 3 次。 Is there any way to avoid this behavior?有什么办法可以避免这种行为? I' have been reading the documentation, but didn't find anyting about this.我一直在阅读文档,但没有找到任何相关信息。

Thanks!谢谢!

It retries when it is an unhandled failure (an error that you didn't catch) or if you handled it but still told Lambda to retry (eg in Node, when you call callback() with a non-null first argument).当它是一个未处理的故障(一个你没有捕获的错误)或者如果你处理了它但仍然告诉 Lambda 重试(例如,在 Node 中,当你用一个非空的第一个参数调用callback()时),它会重试。

To stop it from retrying, you should make sure that any error is handled and you tell Lambda that your invocation finished successfully by returning a non-error (or in Node, calling callback(null, <any>) .要阻止它重试,您应该确保处理任何错误,并通过返回非错误(或在 Node 中调用callback(null, <any>)告诉 Lambda 您的调用已成功完成。

To do this you can enclose the entire body of your handler function with a try-catch.为此,您可以使用 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')
  }
}

As for failures due to timeouts there are things you can do.至于由于超时导致的失败,您可以做一些事情。

If it times out outside of your handler, there's usually something wrong with your code (eg incorrect database config, etc) that you should look at.如果它在您的处理程序之外超时,您应该查看您的代码通常有问题(例如,不正确的数据库配置等)。

If it times out inside your handler during an invocation, there is something you can do about it.如果它在调用期间您的处理程序中超时,您可以采取一些措施。

  • If it's an HTTP request, you should set the timeout of the request to be shorter than your Lambda's timeout, this way it will fail properly and you can catch it.如果是 HTTP 请求,您应该将请求的超时设置为比您的 Lambda 的超时更短,这样它就会正常失败并且您可以捕获它。
  • If it's a database connection, you can probably set a timeout using the library that you're using.如果它是数据库连接,您可能可以使用您正在使用的库设置超时。
  • If it's your logic that times out, you can upgrade the Lambda to use higher memory-CPU to make it faster.如果是您的逻辑超时,您可以升级 Lambda 以使用更高内存的 CPU 以使其更快。 You can also check context.getRemainingTimeInMillis() to know if the Lambda is about to timeout, so you can handle it earlier.您还可以检查context.getRemainingTimeInMillis()以了解 Lambda 是否即将超时,以便您可以更早地处理它。

EDITED : It's now possible to change the lambda settings to disable retries (see announcement )编辑:现在可以更改 lambda 设置以禁用重试(参见公告


Original answer :原答案

There isn't a way to disable retry behavior of Lambda functions.没有办法禁用 Lambda 函数的重试行为。 I suggest two options to deal with that:我建议有两种选择来解决这个问题:

  1. Make your Lambda able to handle retry cases correctly.让您的 Lambda 能够正确处理重试案例。 You can use context.AwsRequestId (or corresponding field) that will be the same when a Lambda is retried.您可以使用重试 Lambda 时相同的 context.AwsRequestId(或相应字段)。
  2. Put your Lambda inside a state machine (using AWS Step Functions).将您的 Lambda 放入状态机中(使用 AWS Step Functions)。 You can only then disable retries.您只能然后禁用重试。 This blog post I've written gives a more general explanation.我写的这篇博文给出了更一般的解释。

If you call the function asynchronously, in the Console , under Function configuration , you can modify the Retry attempts :如果您异步调用该函数,请在Console中的Function configuration下修改Retry attempts

在此处输入图像描述

Since November 2019 , it is possible to set the retry count to 0.2019 年 11 月起,可以将重试次数设置为 0。

That means the lambda will not be retried on error.这意味着 lambda 不会在出错时重试。

As mentioned before, this feature has been added lately.如前所述,最近添加了此功能。 To achieve this behaviour using cloudformation you will need both an AWS::Lambda::Version and AWS::Lambda::EventInvokeConfig :要使用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

If using python then need to put the code in try/catch block as well however there will be no callback.如果使用 python,则还需要将代码放在 try/catch 块中,但是不会有回调。 For example:例如:

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

Since the error has been handled, Lambda will not retry.由于错误已得到处理,Lambda 不会重试。

If you are using Python, I recommend you to follow this thread .如果您使用的是 Python,我建议您关注此主题

If you are using Java, inside handleRequest method add this lines:如果您使用的是 Java,请在handleRequest方法中添加以下行:

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

Use below code to identify and stop retry when there is a failure.使用下面的代码来识别并在出现故障时停止重试。

  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;
      }
    };

you can read more about it here你可以在这里阅读更多相关信息

I achieved this by placing the following line of code:我通过放置以下代码行实现了这一点:

callback(null, "message");回调(空,“消息”);

Into my function such as the below update to DynamoDB.进入我的功能,例如下面对 DynamoDB 的更新。 When there is an error, rather than retrying for hours on end, this callback outside of the if / else will stop the retries.当出现错误时,不是连续重试几个小时,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");
        });

You can also just return true , for example, if you're invoking a Lambda function, using Node.JS.您也可以只返回 true ,例如,如果您使用 Node.JS 调用 Lambda 函数。

I want to stop running the Lambda function, if there's no data.如果没有数据,我想停止运行 Lambda 函数。

So I check for an empty object being returned from the API.所以我检查从 API 返回的空对象。

If it's empty, I return true, and the Lambda is stopped, and the EventBridge is also not re-tried.如果它是空的,我返回 true,Lambda 停止,EventBridge 也不会重试。

This worked for me.这对我有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM