kakakakakku blog

Weekly Tech Blog: Keep on Learning!

AWS Step Functions で AWS Lambda 関数を使わず Amazon S3 にオブジェクトをアップロードする

AWS Step Functions でワークフローを構築しているときに AWS Step Functions の実行時に渡すインプットの一部をファイルとして Amazon S3 に保存したいという場面があったりする❗️実際に最近あった \( 'ω')/

もちろん AWS Lambda 関数を追加すれば柔軟で自由度高くワークフローを拡張できるけど,比較的シンプルな処理であれば無理に AWS Lambda 関数を増やすのではなく,AWS Step Functions の「AWS SDK 統合」を活用する方が良かったりする.ちなみにシンプルな処理であれば AWS Lambda 関数は不要というベストプラクティスは「直接統合 (Direct Integrations)」という表現で AWS Well-Architected Framework Serverless Applications Lens に載っている👌

docs.aws.amazon.com

ワークフロー

今回は動作確認のために AWS SDK 統合 s3:PutObject のみを設定する.

そして,アップロードする Amazon S3 バケットのオブジェクトキーは AWS Step Functions の実行名とインプットとして渡す name を組み合わせるため,AWS Step Functions の組み込み関数 States.Format と AWS Step Functions のコンテキストオブジェクト $$.Execution.Name を設定する.

docs.aws.amazon.com

docs.aws.amazon.com

今回は AWS CDK でワークフローを実装した.

import {
  Stack,
  StackProps,
  aws_s3,
  aws_stepfunctions,
  aws_stepfunctions_tasks,
} from 'aws-cdk-lib'
import { Construct } from 'constructs'

export class SandboxCdkStepfunctionsPutObjectStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props)

    const bucket = new aws_s3.Bucket(this, 'Bucket', {
      bucketName: 'kakakakakku-sandbox-stepfunctions-put-object',
    })

    const putObjectTask = new aws_stepfunctions_tasks.CallAwsService(this, 'PutObjectTask', {
      service: 's3',
      action: 'putObject',
      parameters: {
        'Bucket': bucket.bucketName,
        'Key.$': `States.Format('{}/{}', $$.Execution.Name, $.name)`,
        'Body.$': '$.body',
        'ContentType': 'application/json',
      },
      iamResources: ['*'],
    })

    new aws_stepfunctions.StateMachine(this, 'SandboxCdkStepfunctions', {
      stateMachineName: 'sandbox-cdk-stepfunctions-put-object',
      definitionBody: aws_stepfunctions.DefinitionBody.fromChainable(putObjectTask),
    })
  }
}

最終的にデプロイされたワークフロー定義は以下👌

{
  "StartAt": "PutObjectTask",
  "States": {
    "PutObjectTask": {
      "End": true,
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:s3:putObject",
      "Parameters": {
        "Bucket": "kakakakakku-sandbox-stepfunctions-put-object",
        "Key.$": "States.Format('{}/{}', $$.Execution.Name, $.name)",
        "Body.$": "$.body",
        "ContentType": "application/json"
      }
    }
  }
}

動作確認

2種類のインプットを準備して,ワークフローを実行する❗️

{
    "name": "sandbox001.json",
    "body": {
        "title": "title001",
        "body": "body001"
    }
}
{
    "name": "sandbox002.json",
    "body": {
        "title": "title002",
        "body": "body002"
    }
}

すると,期待通りに Amazon S3 バケットにオブジェクトが追加されている👌

$ aws s3api list-objects --bucket kakakakakku-sandbox-stepfunctions-put-object | jq -r '.Contents[].Key'
f32ea288-3103-4c8a-9b65-6c57298420f8/sandbox002.json
f5f16907-279b-447a-9e1c-eddc44ea78e3/sandbox001.json

そして f5f16907-279b-447a-9e1c-eddc44ea78e3/sandbox001.json を開くと,期待通りにインプットの body に指定した JSON になっていた👌

{"title":"title001","body":"body001"}