使用 boto 调用 lambda 函数我该如何异步调用?

Using boto to invoke lambda functions how do I do so asynchronously?

所以我正在使用 boto 来调用我的 lambda 函数并测试我的后端。我想异步调用它们。我注意到 "invoke_async" 已弃用,不应使用。相反,您应该使用 "invoke" 和 "Event" 的 InvocationType 来异步执行该功能。

虽然 return 我似乎无法弄清楚如何从函数中获取响应。我尝试了以下方法:

payload3=b"""{
"latitude": 39.5732160891,
"longitude": -119.672918997,
"radius": 100
}"""

client = boto3.client('lambda')
for x in range (0, 5):
    response = client.invoke(
        FunctionName="loadSpotsAroundPoint",
        InvocationType='Event',
        Payload=payload3
    )
    time.sleep(15)
    print(json.loads(response['Payload'].read()))
    print("\n")

即使我告诉代码休眠 15 秒,当我尝试打印响应变量时它仍然是空的。如果我将调用 InvokationType 更改为 "RequestResponse" 它一切正常并且打印响应变量,但这是同步的。我错过了什么容易的事吗?我如何执行一些代码,例如打印出结果,当异步调用 returns??

谢谢。

异步执行的 AWS Lambda 函数不会 return 执行结果。如果异步调用请求成功(即没有由于权限等原因导致的错误),AWS Lambda 会立即 return 发送 HTTP 状态代码 202 ACCEPTED 并且不承担进一步传达任何结果信息的责任此异步调用。

来自 AWS Lambda Invoke action 的文档:

Response Syntax

HTTP/1.1 StatusCode
X-Amz-Function-Error: FunctionError
X-Amz-Log-Result: LogResult

Payload

Response Elements

If the action is successful, the service sends back the following HTTP response.

StatusCode

The HTTP status code will be in the 200 range for successful request. For the RequestResponse invocation type this status code will be 200. For the Event invocation type this status code will be 202. For the DryRun invocation type the status code will be 204.

[...]

The response returns the following as the HTTP body.

Payload

It is the JSON representation of the object returned by the Lambda function. This is present only if the invocation type is RequestResponse.

'async AWS lambda invocation''async python code'是有区别的。当您将 InvocationType 设置为 'Event'by definition 时,它永远不会发回响应。

在您的示例中,invoke() 立即 returns None,并且不会在后台隐式启动任何内容以在以后更改该值(谢天谢地!)。因此,当您在 15 秒后查看 response 的值时,它仍然是 None.

看来您真正想要的是 RequestResponse 调用类型,具有异步 Python 代码。您有很多选项可供选择,但我最喜欢的是 concurrent.futures. Another is threading.

这是一个使用 concurrent.futures 的例子:

(如果您使用 Python2,则需要 pip install futures

from concurrent.futures import ThreadPoolExecutor
import json

payload = {...}

with ThreadPoolExecutor(max_workers=5) as executor:
    futs = []
    for x in xrange(0, 5):
        futs.append(
            executor.submit(client.invoke,
                FunctionName   = "loadSpotsAroundPoint",
                InvocationType = "RequestResponse",
                Payload        = bytes(json.dumps(payload))
            )
        )
    results = [ fut.result() for fut in futs ]

print results

您可能想要研究的另一种模式是使用 Event 调用类型,并让您的 Lambda 函数将消息推送到 SNS,然后由另一个 Lambda 函数使用。您可以查看有关 SNS 触发的 lambda 函数的教程 here.

以下是一个 python 函数,它接受要调用的 lambda-function-Name 和要发送到该函数的负载。

通过boto3客户端调用lambda函数

import boto3, json, typing

def invokeLambdaFunction(*, functionName:str=None, payload:typing.Mapping[str, str]=None):
    if functionName == None:
        raise Exception('ERROR: functionName parameter cannot be NULL')
    payloadStr = json.dumps(payload)
    payloadBytesArr = bytes(payloadStr, encoding='utf8')
    client = boto3.client('lambda')
    return client.invoke(
        FunctionName=functionName,
        InvocationType="RequestResponse",
        Payload=payloadBytesArr
    )

和用法:

if __name__ == '__main__':
    payloadObj = {"something" : "1111111-222222-333333-bba8-1111111"}
    response = invokeLambdaFunction(functionName='myLambdaFuncName',  payload=payloadObj)
    print(f'response:{response}')