この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、CX事業本部 IoT事業部の若槻です。
今回は、AWS CDKでのAWS Step Functionsステートマシンの構築で、LambdaInvokeでのpayloadResponseOnly
の指定による動作の違いを確認してみました。
LambdaInvokeとは
ステートマシンからLambda関数を実行するタスクをAWS CDKで実装したい場合、CallAwsServiceまたはLambdaInvokeのコンストラクトを使用します。
CallAwsServiceは、AWSサービスのAPIを汎用的に叩けるコンストラクトです。
LambdaInvokeは、Lambda関数を実行するためのコンストラクトです。
LambdaInvokeの方が高レベルで使用可能なプロパティが限られていますが、大抵の場合はこちらの使用で対応可能です。
そしてこのコンストラクトにはpayloadResponseOnly
というプロパティがあります。指定はオプションで、既定ではfalse
となります。
payloadResponseOnly?
Type: boolean (optional, default: false)Invoke the Lambda in a way that only returns the payload response without additional metadata.
The payloadResponseOnly property cannot be used if integrationPattern, invocationType, clientContext, or qualifier are specified. It always uses the REQUEST_RESPONSE behavior.
今回はこのpayloadResponseOnly
のtrue
/false
の指定による動作の違いを確認してみます。
確認してみた
payloadResponseOnly:falseの場合
まずpayloadResponseOnlyがfalse
の場合の動作についてです。
次の通りCDKスタックを作成しました。LambdaInvoke
コンストラクトでpayloadResponseOnly
プロパティでfalse
を指定しています。
lib/aws-cdk-app-stack.ts
import * as cdk from '@aws-cdk/core';
import * as lambdaNodejs from '@aws-cdk/aws-lambda-nodejs';
import * as sfn from '@aws-cdk/aws-stepfunctions';
import * as tasks from '@aws-cdk/aws-stepfunctions-tasks';
export class AwsCdkAppStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const convertValueFormatFunc = new lambdaNodejs.NodejsFunction(
this,
'convertValueFormatFunc',
{
functionName: 'convertValueFormatFunc',
entry: 'src/lambda/handlers/sampleHandler.ts',
}
);
const convertValueFormatTask = new tasks.LambdaInvoke(
this,
'convertValueFormatTask',
{
lambdaFunction: convertValueFormatFunc,
payload: sfn.TaskInput.fromJsonPathAt('$'),
payloadResponseOnly: false //未指定なら既定でfalseとなる
}
);
new sfn.StateMachine(this, 'testStateMachine', {
stateMachineName: 'testStateMachine',
definition: convertValueFormatTask,
});
}
}
Lambda関数のコードは次の通りです。入力されたnumValueプロパティの値を文字列に変換してstrValueプロパティの値としてReturnしています。
src/lambda/handlers/sampleHandler.ts
interface Event {
numValue: number;
}
interface Output {
strValue: string;
}
export const handler = async (event: Event): Promise<Output> => {
return {
strValue: event.numValue.toString(),
};
};
cdk deploy
でデプロイしてステートマシンを作成します。
作成されたステートマシンの定義は下記のようになります。
{
"StartAt": "convertValueFormatTask",
"States": {
"convertValueFormatTask": {
"End": true,
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.AWSLambdaException",
"Lambda.SdkClientException"
],
"IntervalSeconds": 2,
"MaxAttempts": 6,
"BackoffRate": 2
}
],
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {
"FunctionName": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:convertValueFormatFunc",
"Payload.$": "$"
}
}
}
}
このステートマシンに次の入力を指定して実行します。
{
"numValue": 10
}
実行が成功しました。実行結果の履歴は次の通りです。
convertValueFormatTask
のTaskScheduled
(タスクの入力)は次のようになりました。Lambdaの入力ペイロードに、ステートマシンの入力の値が指定できています。
{
"resourceType": "lambda",
"resource": "invoke",
"region": "ap-northeast-1",
"parameters": {
"FunctionName": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:convertValueFormatFunc",
"Payload": {
"numValue": 10
}
},
"timeoutInSeconds": null,
"heartbeatInSeconds": null
}
またconvertValueFormatTask
のTaskStateExited
(タスクの出力)は次のようになりました。Lambda関数の戻り値のペイロードのパスはoutput.Payload
となっています。また戻り値以外に様々なメタデータが取得できています。
{
"name": "convertValueFormatTask",
"output": {
"ExecutedVersion": "$LATEST",
"Payload": {
"strValue": "10"
},
"SdkHttpMetadata": {
"AllHttpHeaders": {
"X-Amz-Executed-Version": [
"$LATEST"
],
"x-amzn-Remapped-Content-Length": [
"0"
],
"Connection": [
"keep-alive"
],
"x-amzn-RequestId": [
"0bb36b3d-f415-46bb-a540-bffa15d86e4d"
],
"Content-Length": [
"17"
],
"Date": [
"Wed, 15 Dec 2021 14:59:04 GMT"
],
"X-Amzn-Trace-Id": [
"root=1-61ba02b8-2e7068885bd4927a41f93ee8;sampled=0"
],
"Content-Type": [
"application/json"
]
},
"HttpHeaders": {
"Connection": "keep-alive",
"Content-Length": "17",
"Content-Type": "application/json",
"Date": "Wed, 15 Dec 2021 14:59:04 GMT",
"X-Amz-Executed-Version": "$LATEST",
"x-amzn-Remapped-Content-Length": "0",
"x-amzn-RequestId": "0bb36b3d-f415-46bb-a540-bffa15d86e4d",
"X-Amzn-Trace-Id": "root=1-61ba02b8-2e7068885bd4927a41f93ee8;sampled=0"
},
"HttpStatusCode": 200
},
"SdkResponseMetadata": {
"RequestId": "0bb36b3d-f415-46bb-a540-bffa15d86e4d"
},
"StatusCode": 200
},
"outputDetails": {
"truncated": false
}
}
payloadResponseOnly:trueの場合
次にpayloadResponseOnlyがtrue
の場合の動作についてです。
LambdaInvokeコンストラクトでpayloadResponseOnlyプロパティを
true`に修正します。
lib/aws-cdk-app-stack.ts
const convertValueFormatTask = new tasks.LambdaInvoke(
this,
'convertValueFormatTask',
{
lambdaFunction: convertValueFormatFunc,
payload: sfn.TaskInput.fromJsonPathAt('$'),
payloadResponseOnly: true
}
);
Lambda関数は修正しないでおきます。cdk deploy
でタスクの変更をデプロイします。
作成されたステートマシンの定義は下記のようになります。payloadResponseOnly:false
の場合とdiffで比較すると、Resource
とParameters
の指定が異なっています。
{
"StartAt": "convertValueFormatTask",
"States": {
"convertValueFormatTask": {
"End": true,
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.AWSLambdaException",
"Lambda.SdkClientException"
],
"IntervalSeconds": 2,
"MaxAttempts": 6,
"BackoffRate": 2
}
],
"Type": "Task",
+ "Resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:convertValueFormatFunc",
+ "Parameters": "$"
- "Resource": "arn:aws:states:::lambda:invoke",
- "Parameters": {
- "FunctionName": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:convertValueFormatFunc",
- "Payload.$": "$"
- }
}
}
}
このステートマシンに先程と同じく次の入力を指定して実行します。
{
"numValue": 10
}
実行が失敗しました。実行結果の履歴は次の通りです。
convertValueFormatTask
のTaskScheduled
(タスクの入力)は次のようになりました。Lambdaの入力ペイロードで$
が解決できておらず、ステートマシンの入力の値が指定できていません。
{
"resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:convertValueFormatFunc",
"input": "$",
"inputDetails": {
"truncated": false
},
"timeoutInSeconds": null
}
またconvertValueFormatTask
のTaskStateExited
(タスクの出力)は次のようになりました。案の定Lambda関数の実行がエラーとなっています。
{
"error": "TypeError",
"cause": {
"errorType": "TypeError",
"errorMessage": "Cannot read property 'toString' of undefined",
"trace": [
"TypeError: Cannot read property 'toString' of undefined",
" at Runtime.handler (/var/task/index.js:15:30)",
" at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"
]
}
}
payloadResponseOnly:true
の場合はLambdaの入力ペイロードを指定できないようです。
そこでLambda関数で入力は使用せず、出力の値を取得するのみの構成としてみます。
まずLambdaInvokeコンストラクトでpayload
プロパティを削除します。
lib/aws-cdk-app-stack.ts
const convertValueFormatTask = new tasks.LambdaInvoke(
this,
'convertValueFormatTask',
{
lambdaFunction: convertValueFormatFunc,
payloadResponseOnly: true,
}
);
そしてLambda関数のコードを入力を使用しない記述とします。
interface Output {
strValue: string;
}
export const handler = async (): Promise<Output> => {
return {
strValue: '10',
};
};
変更をデプロイしてステートマシンを実行します。
実行が成功しました。実行結果の履歴は次の通りです。
convertValueFormatTask
のTaskStateExited
(タスクの出力)は次のようになりました。Lambda関数の戻り値のペイロードのパスはoutput
となっています。またメタデータなどのペイロード以外のデータは出力されていません。
{
"name": "convertValueFormatTask",
"output": {
"strValue": "10"
},
"outputDetails": {
"truncated": false
}
}
まとめ
LambdaInvokeコンストラクトでのpayloadResponseOnly
の指定の違いをまとめると次のようになりました。
false |
true |
|
---|---|---|
入力ペイロードの指定 | 可能 | 不可 |
出力ペイロードのパス | output.Payload |
output |
出力メタデータ | あり | なし |
Lambda関数で入力ペイロードに応じた処理を行いたい場合はpayloadResponseOnly
をtrue
、そうでない場合はfalse
と指定すれば良さそうですね。
参考
以上