AWS CDKでASL YAMLファイルを読み込んでステートマシンを作る場合、DefinitionBody.fromFile()とdefinitionSubstitutionsプロパティを使おう
データアナリティクス事業本部の笠原です。
みなさん、AWS CDKでStep Functionsのステートマシンを作る際、どのように作りますか?
一般的には、以下のようなコードで DefinitionBody.fromChainable
を使ってコードで記述するケースが多いかと思います。
import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as sfn from 'aws-cdk-lib/aws-stepfunctions'; import * as tasks from 'aws-cdk-lib/aws-stepfunctions-tasks'; import * as lambda from 'aws-cdk-lib/aws-lambda'; declare const submitLambda: lambda.Function; declare const getStatusLambda: lambda.Function; export class SampleStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const submitJob = new tasks.LambdaInvoke(this, 'Submit Job', { lambdaFunction: submitLambda, // Lambda's result is in the attribute `guid` outputPath: '$.guid', }); const waitX = new sfn.Wait(this, 'Wait X Seconds', { time: sfn.WaitTime.secondsPath('$.waitSeconds'), }); const getStatus = new tasks.LambdaInvoke(this, 'Get Job Status', { lambdaFunction: getStatusLambda, // Pass just the field named "guid" into the Lambda, put the // Lambda's result in a field called "status" in the response inputPath: '$.guid', outputPath: '$.status', }); const jobFailed = new sfn.Fail(this, 'Job Failed', { cause: 'AWS Batch Job Failed', error: 'DescribeJob returned FAILED', }); const finalStatus = new tasks.LambdaInvoke(this, 'Get Final Job Status', { lambdaFunction: getStatusLambda, // Use "guid" field as input inputPath: '$.guid', outputPath: '$.Payload', }); const definition = submitJob .next(waitX) .next(getStatus) .next(new sfn.Choice(this, 'Job Complete?') // Look at the "status" field .when(sfn.Condition.stringEquals('$.status', 'FAILED'), jobFailed) .when(sfn.Condition.stringEquals('$.status', 'SUCCEEDED'), finalStatus) .otherwise(waitX)); new sfn.StateMachine(this, 'StateMachine', { definitionBody: sfn.DefinitionBody.fromChainable(definition), timeout: Duration.minutes(5), comment: 'a super cool state machine', }); } }
私はASL YAMLで定義をゴリゴリ書きたい人なので、CDKでもASL YAMLで定義できれば最高です。
VS Codeで書ければ、ステートマシンのプレビューも簡単に確認できます。
DevelopersIOでもCDKにASL YAMLファイルを読み込んでステートマシンを構築している記事がありますが、 aws_stepfunctions.CfnStateMachine()
を使ったり、 AWS SAMの aws_sam.CfnStateMachine()
を使ったりしてます。これらは、いずれもL1コンストラクトで定義してます。
私は、L2コンストラクトである aws_stepfunctions.StateMachine()
を使っています。
あまり記事になっていないようなので、今回はL2コンストラクトでの読み込み方を示します。
実行環境
- Node.js: 20.13.1
- aws-cdk: 2.142.1
- typescript: 5.4.5
CDKでの記述
こんな感じで書けます。
import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import { StateMachine, DefinitionBody } from 'aws-cdk-lib/aws-stepfunctions'; export class SampleStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // Lambda const fn = new lambda.Function(this, 'myFunction', { // 省略 }); // State Machine const mainStateMachine = new StateMachine(this, 'mainStateMachine', { stateMachineName: 'mainStateMachine', definitionBody: DefinitionBody.fromFile( 'src/step_functions/state_machines/main_state_machine.asl.yaml', ), definitionSubstitutions: { myFunctionArn: fn.functionArn, }, }); } }
StateMachine()
クラスのInitializerで、Construct Propsの definitionBody
プロパティと definitionSubstitutions
プロパティを使います。
definitionBody
プロパティでは DefinitionBody.fromFile()
メソッドを使って、ASL YAMLファイルを読み込めます。 fromFile()
メソッドでは、ASL JSONファイルも読み込めます。
definitionSubstitutions
プロパティでは ASL YAMLファイル内に記載されたプレースホルダーを置換するマッピングをkey-valueで定義します。
ちなみに、 DefinitionBody.fromFile()
の他に DefinitionBody.fromString()
メソッドもあります。
こちらはASL JSON文字列を渡すことができますが、残念ながらASL YAML文字列を渡すとエラーになります。
ASL YAMLでの記述
ASL YAMLファイルは以下のように、記述します。
プレースホルダーは ${}
で定義します。
Comment: >- Main State Machine StartAt: MainExec States: MainExec: Type: Task Resource: ${myFunctionArn} End: true
まとめ
意外と簡単にL2コンストラクトでも使えます。
どうしてもL1コンストラクトで定義しないといけない場合を除いて、できるだけL2コンストラクトで定義するとコードがスッキリしますね。