lambda 触发器回调与 context.done
Posted
技术标签:
【中文标题】lambda 触发器回调与 context.done【英文标题】:lambda trigger callback vs context.done 【发布时间】:2019-07-17 16:40:24 【问题描述】:我按照指南 here 设置了预注册触发器。
但是,当我使用 callback(null, event)
时,我的 lambda 函数永远不会真正返回,我最终会得到一个错误
代码:'UnexpectedLambdaException', 名称:'UnexpectedLambdaException', 消息:'arn:aws:lambda:us-east-2:642684845958:function:proj-dev-confirm-1OP5DB3KK5WTA 在调用 Lambda 函数时因错误套接字超时而失败。'
我发现了一个类似的link here,它说要使用context.done()
。
切换后效果很好。
有什么区别?
exports.confirm = (event, context, callback) =>
event.response.autoConfirmUser = true;
context.done(null, event);
//callback(null, event); does not work
【问题讨论】:
context.done()
在 6.10 之前的 Node.js 运行时中使用并且已弃用。将其改回callback()
,我希望它会再次起作用,因为您遇到的错误似乎是您不应该导致的错误,即使是偶然的。它可能已被“修复”,因为您更改了代码中的 任何内容,促使 Lambda 重新部署它。
所以这实际上并没有解决它。但是,我确实添加了context.callbackWaitsForEmptyEventLoop = false;
,它现在可以工作了。你有没有机会解释这实际上是做什么的? @Michael-sqlbot
我也有这个问题。 context.callbackWaitsForEmptyEventLoop = false;解决了
【参考方案1】:
回到 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 和 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 应该被设计为包含逻辑以使其成为预期的、定义的错误,而不是将其归类为“意外”。
【讨论】:
这篇文章写得很好,文档也很好,谢谢。我确实有一个全局数据库连接,这导致了这种情况。这个函数虽然不使用连接,所以我相信使用context.callbackWaitsForEmptyEventLoop = false;
是安全的
@TemporaryFix 或者您可以在完成后关闭连接,而如果 lambda 有点复杂,您可能会忘记一些未完成的调用。我建议仅将 context.callbackWaitsForEmptyEventLoop = false
用于超小的 lambda,尽管 idk 你的 lambda :)【参考方案2】:
作为更新,Runtime Node.js 10.x 处理程序支持async function,它利用return
和throw
语句分别返回成功或错误响应。此外,如果您的函数执行异步任务,那么您可以返回一个Promise
,然后您将使用resolve
或reject
分别返回成功或错误。这两种方法都不需要 context
或 callback
向调用者发出完成信号,从而简化了事情,因此您的 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
,但它不需要发出完成信号。
【讨论】:
现在也支持 Node 12!以上是关于lambda 触发器回调与 context.done的主要内容,如果未能解决你的问题,请参考以下文章
API Gateway 方法与 lambda 函数集成,但 lambda 函数声称它没有触发器
如何创建一个填充了 C 风格函数指针和 lambda 的向量(有和没有捕获)