首页 > 解决方案 > 你能在 Lambda Python 3.6 中有一个异步处理程序吗?

问题描述

我以前做过 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'

标签: pythonamazon-web-servicesaws-lambdaasync-awaitpython-3.6

解决方案


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

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

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

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


推荐阅读