aws lambda函数为单个事件多次触发

Posted

技术标签:

【中文标题】aws lambda函数为单个事件多次触发【英文标题】:aws lambda function triggering multiple times for a single event 【发布时间】:2015-11-10 21:30:02 【问题描述】:

我正在使用 aws lambda 函数将存储桶中上传的 wav 文件转换为 mp3 格式,然后将文件移动到另一个存储桶。它工作正常。但是触发有问题。当我上传小 wav 文件时,lambda 函数被调用一次。但是当我上传一个大尺寸的wav文件时,这个功能会被多次触发。

我google了这个问题,发现它是无状态的,所以会被多次调用(不确定这个触发器是多次上传还是同一次上传)。

https://aws.amazon.com/lambda/faqs/

有没有什么方法可以为单次上传调用一次该函数?

【问题讨论】:

“不确定这个触发器是用于多次上传还是同一次上传” ...看起来这不应该是你应该首先解决的问题吗?无国籍与它无关。检查实际的事件内容,创建您在 S3 事件中接收到的内容的日志并将其存储以供查看,并且解释应该变得显而易见。最有可能的是,您最初用于上传对象的行为所执行的 S3 操作比您意识到的要多。 您需要用更具体的信息来扩展这个问题。理想情况下是代码示例。 听起来上传被分成几部分。您需要创建一个事件,指定该事件仅在 s3:ObjectCreated:CompleteMultiPartUpload 上执行,this tutorial 显示了如何做到这一点,只需将 s3:ObjectCreated:* 替换为 s3:ObjectCreated:CompleteMultiPartUpload 【参考方案1】:

短版: 尝试在 lambda 函数配置中增加超时设置。

加长版:

我猜你在这里遇到了正在超时的 lambda 函数。

S3 事件本质上是异步的,侦听 S3 事件的 lambda 函数在该事件被拒绝之前至少重试 3 次。您提到您的 lambda 函数在您进行转换和重新上传的较小大小的上传期间仅执行一次(没有错误)。从您的代码转换和重新上传所需的时间有可能大于您的 lambda 函数的超时设置。

因此,您可能想尝试在 lambda 函数配置中增加超时设置。

顺便说一句,确认您的 lambda 函数被多次调用的一种方法是查看 cloudwatch 日志中的事件 id (67fe6073-e19c-11e5-1111-6bqw43hkbea3) 发生 -

START RequestId: 67jh48x4-abcd-11e5-1111-6bqw43hkbea3 Version: $LATEST

此事件 ID 表示为其调用 lambda 的特定事件,并且对于负责同一 S3 事件的所有 lambda 执行应该相同。

此外,您可以在以下日志行中查找执行时间(持续时间),该日志行标志着一次 lambda 执行结束 -

REPORT RequestId: 67jh48x4-abcd-11e5-1111-6bqw43hkbea3  Duration: 244.10 ms Billed Duration: 300 ms Memory Size: 128 MB Max Memory Used: 20 MB

如果不是一个解决方案,它至少会给你一些空间,让你在正确的方向上进行调试。告诉我进展如何。

【讨论】:

+1 不特定于 S3,对我来说,这也发生在 CloudWatch Lambda 触发器上。除了增加超时之外,是否有其他选项可以防止这种情况发生。 我的每次发射 3 次。它从 dynamoDB 读取并存储在另一个表中。每次 3 个不同的请求 ID 我认为这里的答案表明它并不总是超时:***.com/questions/57286268/… & aws-labs 最近添加了一些开源工具来标准化处理多次执行的问题:awslabs.github.io/aws-lambda-powertools-python/api/utilities/… 【参考方案2】:

context 对象包含有关您当前正在处理的请求 ID 的信息。即使同一事件多次触发,此 ID 也不会更改。您可以在每次触发事件时保存此 ID,然后检查您处理的最后一个 ID 是否与当前 ID 不同。

这是我解决此问题的最终代码(带有 MongooseJS 数据库处理程序的 NodeJS):

exports.handler = function(event, context, lambdaCallback)         
    Events.findOneAndUpdate(
         name: 'some-event-name' , 
         lastRequestId: context.awsRequestId ).then(function(event) 
        
        if(event.lastRequestId == context.awsRequestId) 
            return;
        

        /* Run the actual job */
        ...
    );

希望这会有所帮助!

【讨论】:

感谢@maxpaj,如果python处理程序有任何类似的选项,请告诉我们。我正在从 lamda 函数请求 .post 到我的应用程序端点。如果响应状态代码需要超过 3 秒。它正在重新使用它,添加提取功能触发器。 我对这个实现有一些问题。我有一次调用 lambda 函数的云监视事件,并注意到它会随机多次运行该函数,但每个函数都有一个与之关联的不同 requestId。 你能检查你的函数是否超时? @skrusetvt @neo73 我检查了我的 CloudWatch 日志,没有抛出任何错误。但是,我确实将超时时间从 15 秒增加到 3 分钟,而且我再也没有看到这种行为了。【参考方案3】:

多次执行 Lambda 的任何事件都是由于 AWS document 中指定的 Lambda 重试行为。

您的代码可能会引发异常、超时或内存不足。执行代码的运行时可能会遇到错误并停止。您可能会耗尽并发性并受到限制。

Lambda 中可能存在一些错误,导致调用 Lambda 函数的客户端或服务重试。

使用 CloudWatch 日志查找错误并解决它可以解决问题。

我也遇到了同样的问题,在我的情况下是因为应用程序错误,解决它对我有帮助。

最近 AWS Lambda 有新的属性来改变默认的重试性质。在异步调用设置下将重试次数设置为 0(默认为 2)。

【讨论】:

就我而言,绝对没有错误,我的超时时间是 10 分钟,这远远超过了我的需要。您认为使用finally 可能会导致这种行为吗? 解决应用程序错误通常被认为是一种好的做法。 我的问题是这种情况的一个特殊实例:我从处理程序返回的结果(所以我在函数中做的最后一件事)不可序列化导致异常,因此事件需要重试。 CloudWatch 日志是您的朋友。【参考方案4】:

在 Lambda 配置中查找“异步调用”有一个选项“重试尝试”,它是函数返回错误时重试的最大次数。

这里还可以配置死信队列服务

【讨论】:

我试过这个并设置为 0,但我的 lambda 仍然重试。

以上是关于aws lambda函数为单个事件多次触发的主要内容,如果未能解决你的问题,请参考以下文章

AWS Cloudwatch/Lambda - 计划事件触发太频繁

如何从外部 SQS 队列活动触发 AWS Lambda 函数

在单个 S3 对象上传事件上触发多个 lambda

如何使用AWS Lambda和SNS事件触发Spring Cloud功能的重试

Cloudformation 模板在 S3 事件上触发 Lambda

AWS Cognito 用户池的事件触发器对象