AWS Lambda 将并发执行次数增加到 15 次,然后在lambda_handler内停止执行代码,然后降至 1 次并发执行

AWS Lambda ramps up to 15 concurrent executions and then stops executing code inside lambda_handler before dropping to 1 concurrent execution

提问人:Jonathan Garvey 提问时间:11/12/2023 最后编辑:Jonathan Garvey 更新时间:11/13/2023 访问量:97

问:

我有一个超时 900 秒(15 分钟)的 AWS Lambda 函数。它被设置为使用 EventBridge 计划每 20 分钟运行一次。此外,在代码中,有逻辑,一旦达到 14 分钟的运行时间,它就会结束函数。它运行得很完美。

然后,我将函数的预留并发限制更改为 15,并将 EventBridge 计划更改为每 1 分钟一次。这就是它开始变得奇怪的地方。

enter image description here

该函数每一分钟触发一次,但一旦达到 15 个并发执行,它似乎已经停止执行 lambda_handler 函数中包含的代码。然后,并发执行的数量从 15 个下降到 1 个。我所说的函数代码没有被执行的意思是:

enter image description here

请注意,整个执行过程需要 1.74 毫秒。我在 lambda_handler() 的正下方放置了一个 print() 语句,看看它是否被执行了,但它甚至没有走那么远。看起来好像函数被调用了,但其中的任何代码都没有被执行。有趣的是,如果我更新函数并重新部署,它会再次恢复正常运行并执行代码。这将表明冷启动工作正常,但暖实例行为不正常。

我启用了 X 射线,它真正显示的是函数执行持续了 2 毫秒。还有什么我可以看的吗?

任何想法将不胜感激。谢谢。

更新 1(Lambda 函数代码)

注意 - 我隐藏了 process_symbol() 的实现,因为它只是下载股票代码的数据并将其保存到 S3。

import os
import json
import s3fs
import urllib3

from datetime import datetime

MAX_RUNNING_TIME_SECONDS = 900

# Timing
start_execution_time = datetime.now()

def get_execution_time_remaining():

    return MAX_RUNNING_TIME_SECONDS - (datetime.now() - start_execution_time).seconds

def lambda_handler(event, context):

    print('Execution beginning')

    symbols = []
    execution_time_remaining = get_execution_time_remaining()

    while execution_time_remaining > 60:

        # Get next symbol to load
        symbol_metadata = get_next_symbol_to_load()

        if symbol_metadata:
    
            symbol = symbol_metadata[0]
            symbols.append(symbol)
        
            # process_symbol(symbol)
            # update_rds(symbol)

        execution_time_remaining = get_execution_time_remaining()
        print(f'execution_time_remaining = {execution_time_remaining}')

    return_message = ''
    current_time_text = datetime.now().strftime('%m/%d/%Y, %H:%M:%S.%f')

    if symbols:
        return_message = f"Successfully saved {', '.join(symbols)} to the cloud at {current_time_text}."
    else:
        return_message = f'Successfully execution at {current_time_text} but no symbols were processed.'

    return {
        "statusCode": 200,
        "body": return_message,
    }

更新 2

同样值得注意的是,在它增加到 15 个并发执行并停止执行 lambda 函数中包含的代码后,大约有 80-90 分钟的休息时间,然后它以某种方式再次开始执行函数代码。

enter image description here

python amazon-web-services 函数 aws-lambda 并发

评论

1赞 Maurice 11/12/2023
我认为,如果不看到一些代码,我们将无法真正解决这个问题。输出似乎指示正在执行您的代码。我的猜测是,某些东西对执行上下文被重用感到不满意(或非常高兴并返回缓存的结果),但没有看到代码,它只不过是一种猜测。另一个可疑因素是 stop-if-at-14-mins-logic,因为它可能使用了未正确重置的全局变量。Execution beginning
0赞 Jonathan Garvey 11/13/2023
谢谢莫里斯。请参阅添加到问题的代码。在我看到您的评论之前,我之前返回了相同的return_message文本,即“成功”。此后,我将其更新为返回一个唯一的字符串,认为这可能会欺骗 Lambda 函数不缓存结果。不幸的是,这无济于事。此外,我在代码中隐藏了两个函数的实现,因为它们只负责进行外部 API 调用和下载 CSV 文件。
0赞 Jonathan Garvey 11/13/2023
@Maurice,我将 start_execution_time = datetime.now() 移动到lambda_handler内部,并发实例数稳定在 15 个。我认为在这种情况下,15 将是最大值,因为每个函数的超时时间为 15 分钟,并且每 1 分钟调用一次。将在下面添加一个答案并给你点赞。

答:

1赞 Jonathan Garvey 11/13/2023 #1

正如@Maurice所暗示的那样,在并发场景中,有一个全局变量会影响代码的执行。任务:

start_execution_time = datetime.now()

之前在 lambda_handler() 上方分配的,当移动到它内部时,导致并发按预期工作。这篇博文也很有用:

https://pfisterer.dev/posts/aws-lambda-container-reuse/

因为它讨论了 lambda 如何重用容器以及这可能对执行产生什么影响。