lambda 触发器回调与 context.done

lambda trigger callback vs context.done

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

但是,当我使用 callback(null, event) 时,我的 lambda 函数实际上永远不会 return,我最终会得到一个错误

{ code: 'UnexpectedLambdaException', name: 'UnexpectedLambdaException', message: 'arn:aws:lambda:us-east-2:642684845958:function:proj-dev-confirm-1OP5DB3KK5WTA failed with error Socket timeout while invoking Lambda function.' }

我找到了一个类似的 说要使用 context.done()

切换后完全正常。

有什么区别?

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

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

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

Using the Earlier Node.js Runtime v0.10.42 是 Lambda 文档中不再存在的页面的存档副本,它解释了如何使用这些方法。

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

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

Context.succeed, context.done, and context.fail however, are more than just bookkeeping – they cause the request to return after the current task completes and freeze the process immediately, even if other tasks remain in the Node.js event loop. Generally that’s not what you want if those tasks represent incomplete callbacks.

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 函数立即变为 return 的情况在调用回调之后,无论事件循环中发生了什么。默认值为 true,因为 false 可以掩盖函数中的错误,如果您没有考虑容器重用的影响,可能会导致非常 erratic/unexpected 的行为——因此您不应将其设置为false 除非并且直到您明白为什么需要它。

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

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

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

那么,我们如何解析 Cognito 错误?起初,它似乎很不寻常,但现在很明显它不是。

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

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

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

对我来说,如果错误是这样的话,问题会更清楚:

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

这种格式会更清楚地表明,虽然 Cognito 正在调用该函数,但它引发了一个内部 Socket timeout 错误(与 Lambda 遇到意外的内部错误,这是我最初的——但不正确的——假设)。

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

作为更新,运行时 Node.js 10.x 处理程序支持 async function,它使用 returnthrow 语句到 return分别是成功或错误响应。此外,如果您的函数执行异步任务,那么您可以 return 一个 Promise 然后您将使用 resolvereject 来分别 return 成功或错误.这两种方法都不需要 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,但它不需要发出完成信号。