13

我正在按照此处的指南设置预注册触发器。

但是,当我使用callback(null, event)我的 lambda 函数时,我将永远不会真正返回,我最终会得到一个错误

{ 代码:'UnexpectedLambdaException',名称:'UnexpectedLambdaException',消息:'arn:aws:lambda:us-east-2:642684845958:function:proj-dev-confirm-1OP5DB3KK5WTA 在调用 Lambda 函数时因错误套接字超时而失败。' }

我在这里找到了一个类似的链接,上面写着使用context.done().

切换后它工作得很好。

有什么不同?

exports.confirm = (event, context, callback) => {
    event.response.autoConfirmUser = true;
    context.done(null, event);
    //callback(null, event); does not work
}
4

2 回答 2

31

回到 Node.js 0.10 的原始 Lambda 运行时环境,Lambda 在context对象中提供了帮助函数:context.done(err, res) context.succeed(res)context.fail(err).

这是以前记录的,但已被删除。

使用较早的 Node.js 运行时 v0.10.42是 Lambda 文档中不再存在的页面的存档副本,它解释了如何使用这些方法。

当 Lambda 的 Node.js 4.3 运行时启动时,这些仍然是为了向后兼容(并且仍然可用但未记录),callback(err, res)并被引入。

这是您的问题的性质,以及为什么您找到的两个解决方案实际上似乎可以解决它。

然而,Context.succeed、context.done 和 context.fail 不仅仅是记账——它们会导致请求在当前任务完成后返回并立即冻结进程,即使其他任务仍保留在 Node.js 事件循环中。如果这些任务代表不完整的回调,通常这不是您想要的。

https://aws.amazon.com/blogs/compute/node-js-4-3-2-runtime-now-available-on-lambda/

因此,使用callback,Lambda 函数现在以更典型的正确方式运行,但如果您打算在调用之间发生的冻结期间将某些对象保留在事件循环中,这将是一个问题——与旧的(不推荐使用的)done fail succeed方法不同,使用回调不会立即暂停事情。相反,它等待事件循环为空。

context.callbackWaitsForEmptyEventLoop-- 默认true-- 被引入,以便您可以将其设置false为那些您希望 Lambda 函数在您调用回调后立即返回的情况,而不管事件循环中发生了什么。默认值是true因为可以掩盖函数中的错误,并且如果您没有考虑容器重用的含义,可能会导致非常不稳定/意外的行为——因此,除非并且直到您了解为什么需要它,否则false您不应将其设置为。false

需要的一个常见原因false是您的函数建立了数据库连接。如果您在全局变量中创建数据库连接对象,它将有一个打开的套接字,并且可能还有其他东西,如计时器,位于事件循环中。这可以防止回调导致 Lambda 返回响应,直到这些操作也完成或调用超时计时器触发。

确定为什么需要将其设置为false,如果这是一个正当理由,那么使用它是正确的。

否则,在调用回调时,您的代码可能存在您需要了解和修复的错误,例如使请求处于飞行状态或其他工作未完成。

那么,我们如何解析 Cognito 错误呢?起初,这似乎很不寻常,但现在很明显并非如此。

执行函数时,Lambda 会在配置的秒数后抛出任务超时的错误。当您在 Lambda 控制台中测试您的函数时,您应该会发现这就是发生的情况。

不幸的是,Cognito 在调用 Lambda 函数时似乎采用了内部设计捷径,而不是等待 Lambda 使调用超时(这可能会占用 Cognito 内部的资源)或将其自己的显式计时器强加于 Cognito 将等待的最长持续时间一个 Lambda 响应,它依赖于一个较低层的套接字计时器来限制这个等待......因此在调用超时时会抛出一个“意外”错误。

错误消息的解释更加复杂,错误中缺少引号,其中插入了下层异常。

对我来说,如果错误如下所示,问题会更加清楚:

'arn:aws:lambda:...' failed with error 'Socket timeout' while invoking Lambda function

这种格式将更清楚地表明,当Cognito调用该函数时,它引发了内部Socket timeout错误(与Lambda遇到意外的内部错误相反,这是我最初的 - 并且不正确的 - 假设)。

Cognito 对 Lambda 函数施加某种响应时间限制是非常合理的,但我没有看到这一点记录在案。我怀疑您的 Lambda 函数本身的短暂超时(使其更快地失败)会导致 Cognito 抛出一个更有用的错误,但在我看来,Cognito 应该被设计为包含逻辑以使其成为预期的、定义的错误,而不是将其归类为“意外”。

于 2019-02-24T17:53:52.233 回答
5

作为更新,Runtime Node.js 10.x 处理程序支持异步函数,该函数使用returnthrow语句分别返回成功或错误响应。此外,如果您的函数执行异步任务,那么您可以分别返回Promise您将使用的位置resolvereject返回成功或错误。这两种方法都通过不需要contextcallback向调用者发出完成信号来简化事情,因此您的 lambda 函数可能看起来像这样:

exports.handler = async (event) => {
  // perform tasking...
  const data = doStuffWith(event)

  // later encounter an error situation
  throw new Error('tell invoker you encountered an error')

  // finished tasking with no errors
  return { data }
}

当然,您仍然可以使用context,但不需要发出完成信号。

于 2019-07-05T16:24:50.063 回答