【问题标题】:Why does my Lambda function time out even though the API Gateway callback has already been called?为什么我的 Lambda 函数即使已调用 API Gateway 回调也会超时?
【发布时间】:2018-02-14 03:23:49
【问题描述】:

我有一个 AWS API Gateway 方法,可以将请求代理到 AWS Lambda。但是,它会在三秒后出错,并在日志中显示以下内容:

转换前的端点响应正文:{"errorMessage":"2017-09-05T16:30:49.987Z 922186c0-9257-11e7-9db3-51921d5597a2 任务在 3.00 秒后超时"}

因此,我继续检查我的 Node 6.10 AWS Lambda 函数以了解它超时的原因。我在每个函数调用之前和之后添加了日志记录语句。令人惊讶的是,它完成了它应该做的所有事情:调用 API Gateway 回调,然后对数据库运行查询。所有这一切都需要 0.6 秒,据我所知,没有其他代码可以运行。尽管如此,它似乎在剩下的三秒钟内继续运行,然后超时。 (我认为这是因为我打开了与数据库的连接。)

我在callback 调用之前和之后放置的日志语句表明该调用在半秒内执行。然而,该响应似乎无法到达 API Gateway,而三秒后的错误确实

这可能是什么潜在原因,我该如何调试它?

【问题讨论】:

    标签: node.js amazon-web-services aws-lambda aws-api-gateway


    【解决方案1】:

    默认情况下,在 NodeJS Lambda 函数中调用 callback() 函数不会结束函数执行。它将继续运行,直到事件循环为空。当您保持打开数据库连接时,会出现在调用 callback 后继续运行 NodeJS Lambda 函数的常见问题。您尚未发布任何代码,因此我无法给出具体建议,但您需要确定是否在代码中保持数据库连接处于打开状态或类似情况。

    或者,您可以通过在context 对象上设置callbackWaitsForEmptyEventLoop = false 来更改行为,以便在调用callback 函数时立即结束执行。

    【讨论】:

    • 嗯,是的,谈论它也让我想到了那个方向。我实际上是让数据库连接保持打开状态,因为我知道如果 Lambda 容器碰巧被重新使用,它可以被重新使用,但我开始明白这在使用 API Gateway 时不适用.我实际上确实希望继续执行,但我想同时不能真正响应 API 网关。我现在正在考虑关闭数据库连接,但可能就是这样。
    • 默认是true...你想设置callbackWaitsForEmptyEventLoop = false
    • @Michael-sqlbot 对。感谢您指出了这一点。已修复。
    【解决方案2】:

    您的 API 网关有 29 秒的固定超时。大多数查询都会在此时间范围内完成。 将您的 lambda 执行超时增加到 30 秒到 3 分 00 秒之间的任何时间。 使用 context.succeed() 而不是回调。 这对我有用。

    const mysql = require('mysql');
    const connection = mysql.createConnection({
      host     : 'your_mysql_host',
      user     : 'your_mysql_user',
      password : 'your_mysql_password',
      database : 'your_mysql_db'
    });
    
    exports.handler = (event, context) => {
      var userId = event.params.querystring.userid;
      const sql = 'SELECT * FROM users where USER_ID=' + userId;
    
      var response = {
        "statusCode": 200, 
        "body": "body_text_goes_here"
      }
    
      if(userId){
        connection.query(sql, function (error, results, fields) {
          if (error) {
            context.succeed(error);
          } else {
            response.body = results;
            context.succeed(response);
          }
        });
      }
    }
    

    【讨论】:

    • The documentation 似乎暗示 context.succeed 是早期运行时(节点 0.10)的残余,就像 callback 参数一样,它不会导致 Lambda 提前终止函数(在您的代码示例中,该函数仅在 context.succeed 之后终止,因为它是处理程序中的最后一个函数调用)。
    • 虽然它似乎是最后一个函数调用,但是程序并没有终止,因为 mysql 连接仍然打开。因此,回调返回数据不被视为响应(在使用 API 网关的情况下)。这种情况尤其适用于 lambda 与 API 网关结合使用的场景。但是,我在许多函数中的许多 lambda 用法中发现,使用 context.succeed 倾向于通知我的 api 网关返回的结果是它等待的结果。
    【解决方案3】:

    我有同样的问题,我已经更新了我的代码中的超时,但没有运气最终增加了解决我的问题的 lambda 执行时间。

    How to increase an AWS Lambda timeout?

    【讨论】:

    • 这个答案是错误的。那家伙说他的代码运行不到一秒。
    猜你喜欢
    • 2021-04-16
    • 1970-01-01
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    • 2020-10-10
    • 1970-01-01
    • 1970-01-01
    • 2019-01-20
    相关资源
    最近更新 更多