【问题标题】:Can you have an async handler in Lambda Python 3.6?你能在 Lambda Python 3.6 中有一个异步处理程序吗?
【发布时间】:2020-06-12 19:12:21
【问题描述】:

我以前做过 Lambda 函数,但不是在 Python 中。我知道在 Javascript 中 Lambda 支持异步处理函数,但如果我在 Python 中尝试会出错。

这是我要测试的代码:

async def handler(event, context):
    print(str(event))
    return { 
        'message' : 'OK'
    }

这是我得到的错误:

An error occurred during JSON serialization of response: <coroutine object handler at 0x7f63a2d20308> is not JSON serializable
Traceback (most recent call last):
  File "/var/lang/lib/python3.6/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "/var/lang/lib/python3.6/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/var/lang/lib/python3.6/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/var/runtime/awslambda/bootstrap.py", line 149, in decimal_serializer
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <coroutine object handler at 0x7f63a2d20308> is not JSON serializable

/var/runtime/awslambda/bootstrap.py:312: RuntimeWarning: coroutine 'handler' was never awaited
  errortype, result, fatal = report_fault(invokeid, e)

2021 年编辑

由于这个问题似乎越来越受到关注,我假设人们来到这里试图弄清楚如何让 async 像我一样使用 AWS Lambda。坏消息是,即使在一年多之后的现在,AWS 仍然不支持在基于 Python 的 Lambda 函数中使用异步处理程序。 (我不知道为什么,因为基于 NodeJS 的 Lambda 函数可以很好地处理它。)

好消息是,从 Python 3.7 开始,有一个简单的解决方法,形式为 asyncio.run

import asyncio

def lambda_handler(event, context):
    # Use asyncio.run to synchronously "await" an async function
    result = asyncio.run(async_handler(event, context))
    
    return {
        'statusCode': 200,
        'body': result
    }

async def async_handler(event, context):
    # Put your asynchronous code here
    await asyncio.sleep(1)
    
    return 'Success'

【问题讨论】:

  • 我不知道。编程文档只说明了同步def handler(event, context)选项。
  • asyncio.run 不是正确的方法!您将在后续调用时遇到Event loop closed 异常。请参阅下面我的答案中的详细信息。
  • @AntonBryzgalov 我不知道这是否是 Lambda 运行时的问题,因为您的答案已经写好了,但是当我使用 asyncio.get_event_loop() 时,它抛出了一个错误,因为没有现有的事件循环要得到。因此,您必须手动创建事件循环并关闭它,这真的很难管理,这就是我使用asyncio.run 的原因,因为它为您处理创建和关闭循环。我在每个受支持的 Python 运行时 3.7+ 上运行了几次,但从未收到 Event loop closed 异常。
  • @Abion47 是的,如果您不将任何资源(如数据库连接或 HTTP 客户端)附加到循环,这是可能的。或者,如果您在 Lambda 处理程序函数执行中附加所有资源(而不是在全局 Python 范围内)。但是建议在全局范围内定义连接,因为它允许您通过后续调用重用它们(而不是花时间重新建立连接)。
  • @AntonBryzgalov 那么当你的 lambda 不包含任何此类资源或连接时,如何确保存在循环?

标签: python amazon-web-services aws-lambda async-await python-3.6


【解决方案1】:

一点也不。 AWS Lambda不支持异步 Python 处理程序。

如果您需要在 AWS Lambda 中使用 async/await 功能,您必须在代码中定义异步函数(在 Lambda 文件或 Lambda 层中)并在同步处理程序中调用 asyncio.get_event_loop().run_until_complete(your_async_handler()) .

请注意,asyncio.run (introduced in Python 3.7) 不是在 AWS Lambda 执行环境中调用异步处理程序的正确方法,因为 Lambda tries to reuse 是后续调用的执行上下文。这里的问题是asyncio.run 创建了一个新的EventLoop 并关闭了前一个。如果您打开了任何资源或创建了附加到先前 Lambda 调用中关闭的 EventLoop 的协程,您将收到 «Event loop closed» 错误。 asyncio.get_event_loop().run_until_complete 允许您重用相同的循环。请参阅相关的 StackOverflow question

AWS Lambda 文档通过引入同步和异步 调用 稍微误导了读者。不要将它与同步/异步 Python 函数混淆。 Synchronous 是指调用 AWS Lambda 并进一步等待结果(阻塞操作)。该函数会立即被调用,您会尽快得到响应。而使用asynchronous 调用时,您要求 Lambda 安排函数执行,而不是等待响应。到时候,Lambda 还是会同步调用的处理函数。

【讨论】:

  • 我不相信asyncio.run 不是这样做的正确方法。会关闭前一个吗?从文档看来,当前调用负责关闭当前调用。它不会泄漏,因此后续运行必须关闭前一个。 (我说的是只使用asyncio.run 来创建任何循环的情况。)
  • @KrzysztofSzularz 关闭当前循环(也就是上一次调用的循环)不允许您重用附加到当前循环的资源(例如 aiohttp 会话、数据库连接)。请参阅我们在问题 cmets 中的讨论。
猜你喜欢
  • 2018-06-08
  • 2017-07-30
  • 1970-01-01
  • 1970-01-01
  • 2011-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多