はじめに
ChaliceでバックエンドAPIを実装していました。あるAPIは通知やメール送信などを伴い、レスポンスに時間がかかるようになりました。
そこで、時間がかかる処理は別のChalice(Lambda)を起動してそちらでやってもらい、本線の処理はさっさとレスポンスしてしまおう、と思いつきました。
結果としては失敗で、本線がレスポンスして処理を終えると、非同期で起動したLambdaもつられて終了してしまいました。
結局、やりたいことを実現するにはSQSにキューを投げる→別のLambdaを起動してそちらで時間がかかる処理をする、という構成をとることになりました。
この投稿はそんなダメだったことのメモです。
ソースコード
非同期で別のChalice(Lambda)を叩く関数
Lambdaの環境変数に、Chaliceの関数名 FUNCTION_NAME を設定しておきます。Chaliceで自身の関数名を取得する方法がわからなかったので、一度デプロイして、作成された関数の名前を改めて設定する、というイケテナイ感じになりました…。
def invoke_async_function(
method: str,
path: str,
path_parameters: Dict = {},
query_string_parameters: Dict = {},
payload: Dict = {}) -> None:
""" Invoke lambda asyncnously to execute Chalice app API.
:params method: The http method on REST.
:params path: (optional) The path for API. include path parameter placeholders.
:params path_parameters: (optional) The parameters for the path.
:params query_string_parameters: (optional) The query string and parameters for the path.
:params payload: (optional) The data as the request body for API.
see: How to invoke a Chalice Lambda.
https://stackoverflow.com/questions/62815740/how-to-directly-invoke-a-chalice-lambda-from-another-lambda-without-going-throug
see: Docs for invoke lambda.
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lambda.html#Lambda.Client.invoke
"""
headers: Dict = {}
if method in ["POST", "PUT", "PATCH"]:
headers = {
"Content-Type": "application/json"
}
boto3.client("lambda").invoke(
FunctionName=os.environ.get("FUNCTION_NAME"),
InvocationType='Event',
Payload=json.dumps({
'httpMethod': method,
'headers': headers,
'path': path,
'pathParameters': path_parameters,
'queryStringParameters': query_string_parameters,
'multiValueHeaders': {},
'multiValueQueryStringParameters': None,
'stageVariables': None,
'requestContext': {
'authorizer': {'claims': None},
'path': path,
'resourcePath': path,
'httpMethod': method,
},
"body": json.dumps(payload)
}),
)
呼び出し方
invoke_async_function(
"POST",
"/path/to/{param1}/api/{param2}",
path_parameters={"param1": param1, "param2": param2},
payload={"field1": field1, "field2", field2}
)