AWSから割とすごい機能が発表されました。
Introducing AWS Lambda Destinations
https://aws.amazon.com/jp/blogs/compute/introducing-aws-lambda-destinations/
Lambdaの実行結果に従って次のアクション(AWSサービス)を指定できる、というものです。
成功/失敗の条件で流れを制御したい場合には、Step Functionsを使う必要もなく、Lambdaだけで完結することができるようになりました。
早速試してみます。
呼び出し元のLambdaを適当に定義
こんな感じのPythonを書きます。(Python 3.7を利用)
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def destination_sample_handler(event, context):
logger.info("destination sample lambda started.")
if event['Success'] == True:
return {
'statusCode': 200,
'body': event
}
else:
raise Exception('Success is False', event)
呼び出す際、event内にSuccess変数を定義し、その中身がTrueかFalseで判断を変えています。
Destinationを設定する
AWSブログではSNSとLambdaで成功/失敗の呼び出し先を変えてますが、手を抜いて両方Lambdaにしちゃいます。
Lambda関数にアクセスした際に、「Designer」パート「Cofiguration」タグ内に、「Add destination」という項目が見つかるはずです。
成功パターンの中身はこんな感じ。ただLogに出力しているだけです。
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
logger.info("Success dest lambda started.")
logger.info(event)
return {
'statusCode': 200,
'message': 'Success in dest lambda',
'body': event
}
中身は成功パターンと同じです
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
logger.info("Failure dest lambda started.")
logger.info(event)
return {
'statusCode': 200,
'message': "Failure in dest lambda",
'body': event
}
実行してみる
実行はCLIから実施します。
$ aws lambda invoke --function-name destination-sample --invocation-type Event --payload '{ "Success": false }' response.json
{
"StatusCode": 202
}
実行が成功すると202がStatusCodeとして返ってくるようです。
成功
成功させて見ると成功側のCloudWatch Logsにこんな感じの出力がありました。
CloudWatch Logs
[INFO] 2019-11-26T22:26:49.792Z xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx {'version': '1.0', 'timestamp': '2019-11-26T22:26:49.425Z', 'requestContext': {'requestId': '26fab6f9-a2b7-45f2-bce2-47c612cdb8b7', 'functionArn': 'arn:aws:lambda:us-east-1:000000000000:function:destination-sample:$LATEST', 'condition': 'Success', 'approximateInvokeCount': 1}, 'requestPayload': {'Success': True}, 'responseContext': {'statusCode': 200, 'executedVersion': '$LATEST'}, 'responsePayload': {'statusCode': 200, 'body': {'Success': True}}}
呼び出し先のeventの中身をログ出力しましたが、以下のようになっているようです。
- conditionに成功/失敗が入る
- requestPayloadに大元の呼び出し元eventが入る
- responsePayloadに呼び出し元からreturnされた値が入る
少しコードを編集してeventにMessage要素を入れたところ、responsePayloadの中身が追加されました。
if event['Success'] == True:
event['Message'] = "Successful finished."
return {
'statusCode': 200,
'body': event
}
[INFO] 2019-11-26T23:41:21.229Z xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx {'version': '1.0', 'timestamp': '2019-11-26T23:41:20.730Z', 'requestContext': {'requestId': 'ba73f7a2-77f4-4166-a95d-d43020e5cc32', 'functionArn': 'arn:aws:lambda:us-east-1:000000000000:function:destination-sample:$LATEST', 'condition': 'Success', 'approximateInvokeCount': 1}, 'requestPayload': {'Success': True}, 'responseContext': {'statusCode': 200, 'executedVersion': '$LATEST'}, 'responsePayload': {'statusCode': 200, 'body': {'Success': True, 'Message': 'Successful finished.'}}}
ちなみに成功時のDestinationを一つ増やしたところ、On success側の設定が上書きされました。一つの条件に対して呼び出せるサービスは一つのようです。
Add destinationを実施してもOn successの呼び出し先が上書きされるだけ。
失敗
失敗側も似たようなログがCloudWatch Logsに出ました。
[INFO] 2019-11-26T22:30:46.594Z xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx {'version': '1.0', 'timestamp': '2019-11-26T22:30:46.203Z', 'requestContext': {'requestId': '6fc2d258-fafb-40a2-8d18-886df8510fa1', 'functionArn': 'arn:aws:lambda:us-east-1:000000000000:function:destination-sample:$LATEST', 'condition': 'RetriesExhausted', 'approximateInvokeCount': 3}, 'requestPayload': {'Success': False}, 'responseContext': {'statusCode': 200, 'executedVersion': '$LATEST', 'functionError': 'Unhandled'}, 'responsePayload': {'errorMessage': "('Success is False', {'Success': False})", 'errorType': 'Exception', 'stackTrace': [' File "/var/task/lambda_function.py", line 17, in destination_sample_handler\n raise Exception(\'Success is False\', event)\n']}}
Exceptionの中身もきちんと伝搬してますね。
ちなみにX-Rayでの表示は?
X-RayではきちんとLambdaから処理が分岐しました。想像した通りとはいえ、これはすごい。ほぼこれでトレースもできますね。
まとめ
簡単に成功/失敗での処理の分岐が実現できてしまいました。ちょっとしたスクリプトの制御であればこれで十分ですね。