Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Deploy production with AWS CDK / 実践プロダクションサーバーレス

Deploy production with AWS CDK / 実践プロダクションサーバーレス

AWS CDK と TypeScript による Web アプリケーション開発パターン

プロダクションでのアプリケーション構築にサーバーレスを採用することも増えてきました。本セッションではサーバーレスアプリケーションのデプロイを考えます。昨今のクラウドアプリに共通して、デプロイのハードルがかなり上がっています。実際の環境、例えばAWSにあげてみないとわからないことが増えてきたためです。

プロダクションデプロイのハードルを下げるアプローチとして、「デプロイ可能な状態を維持する」方針を立ててみました。そして、そのために AWS CDK が寄与することを述べます。さらに、実際にいくつかの実例を交えて、AWS 構成、その際の AWS CDK コードを説明します。

Avatar for Yusuke Wada

Yusuke Wada

June 26, 2020
Tweet

More Decks by Yusuke Wada

Other Decks in Technology

Transcript

  1. 

  2. લఏɿαʔόʔϨεͷఆٛ  ΦϯϓϨϛε Ϋϥ΢υ FaaS Ϛωʔδυ αʔϏε ΞϓϦέʔγϣϯ ϥϯλΠϜ ϛυϧ΢ΣΞ

    OS Ծ૝Խج൫ ϋʔυ΢ΣΞ Ϣʔβʔ Ϣʔβʔ Ϋϥ΢υϕϯμʔ Ϣʔβʔ Ϋϥ΢υϕϯμʔ Ϋϥ΢υϕϯμʔ αʔϏε੹೚Ϟσϧ
  3. લఏɿαʔόʔϨεͷఆٛ  ΦϯϓϨϛε Ϋϥ΢υ FaaS Ϛωʔδυ αʔϏε ΞϓϦέʔγϣϯ ϥϯλΠϜ ϛυϧ΢ΣΞ

    OS Ծ૝Խج൫ ϋʔυ΢ΣΞ Ϣʔβʔ Ϣʔβʔ Ϋϥ΢υϕϯμʔ Ϣʔβʔ Ϋϥ΢υϕϯμʔ Ϋϥ΢υϕϯμʔ αʔϏε੹೚Ϟσϧ ͜ΕΒΛ૊Έ߹ΘͤΔ͜ͱ
  4. αʔόʔϨε͕ಘҙͳ͜ͱϏδωεޮՌͱ͸  αʔϏεΠϯ· Ͱͷ࣌ؒΛ୹ॖ ୹ظ࣮૷࣮ݱ ػձଛࣦ๷ࢭ ӡ༻ɾอकͷ লྗԽ αʔϏε඼࣭҆ఆԽ ಺੡Խ֦େͷࢧԉ

    ΞδϦςΟ޲্ ݱ৔ཁٻͷਝ଎࣮૷ αʔόʔϨεͷޮՌͱ͸? https://aws.amazon.com/jp/serverless/patterns/serverless-benefit/
  5. "84ΞΧ΢ϯτ΁ͷαʔϏε഑ஔΛܾΊΔ  σϓϩΠ͢ΔͨΊʹඞཁͳࡐྉͷͻͱͭ AWSΞΧ΢ϯτ DEV؀ڥ %&7 αʔϏε# AWSΞΧ΢ϯτ PRD؀ڥ AWSΞΧ΢ϯτ

    αʔϏεA αʔϏε$ αʔϏε" αʔϏε# αʔϏε$ 13% αʔϏε" %&7 AWSΞΧ΢ϯτ αʔϏεB 13% %&7 AWSΞΧ΢ϯτ αʔϏεC 13%
  6. "84ΞΧ΢ϯτ΁ͷαʔϏε഑ஔΛܾΊΔ  AWSΞΧ΢ϯτ DEV؀ڥ %&7 αʔϏε# AWSΞΧ΢ϯτ PRD؀ڥ AWSΞΧ΢ϯτ αʔϏεA

    αʔϏε$ αʔϏε" αʔϏε# αʔϏε$ 13% αʔϏε" %&7 AWSΞΧ΢ϯτ αʔϏεB 13% %&7 AWSΞΧ΢ϯτ αʔϏεC 13% ͪ͜Β͕͓͢͢Ί
  7. "84ΞΧ΢ϯτ΁ͷαʔϏε഑ஔΛܾΊΔ  AWSΞΧ΢ϯτ DEV؀ڥ %&7 αʔϏε# AWSΞΧ΢ϯτ PRD؀ڥ AWSΞΧ΢ϯτ αʔϏεA

    αʔϏε$ αʔϏε" αʔϏε# αʔϏε$ 13% αʔϏε" %&7 AWSΞΧ΢ϯτ αʔϏεB 13% %&7 AWSΞΧ΢ϯτ αʔϏεC 13% ͪ͜Β͕͓͢͢Ί - ΞΧ΢ϯτ͝ͱͷϦιʔε্ݶʹͻ͔͔ͬΓʹ͘͘ͳΔ - ΞΧ΢ϯτͷϥϯχϯάίετ = αʔϏεͷϥϯχϯάίετ - ৽͍͠αʔϏεΛ౤ೖ͢Δͱ͖ɺطଘͷՔಇதαʔϏεΛؾʹʹ͠ͳ͘ ͯΑ͍
  8. αϯϓϧ$MPVE8BUDI&WFOUTͰىಈ͢Δ-BNCEB'VODUJPO  import events = require('@aws-cdk/aws-events'); import targets = require('@aws-cdk/aws-events-targets');

    import lambda = require('@aws-cdk/aws-lambda'); import cdk = require('@aws-cdk/core'); import fs = require('fs'); export class LambdaCronStack extends cdk.Stack { constructor(app: cdk.App, id: string) { super(app, id); const lambdaFn = new lambda.Function(this, 'Singleton', { code: new lambda.InlineCode(fs.readFileSync('lambda-handler.py', { encoding: 'utf-8' })), handler: 'index.main', timeout: cdk.Duration.seconds(300), runtime: lambda.Runtime.PYTHON_3_6, }); // Run every day at 6PM UTC // See https://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule- expressions.html const rule = new events.Rule(this, 'Rule', { schedule: events.Schedule.expression('cron(0 18 ? * MON-FRI *)') }); rule.addTarget(new targets.LambdaFunction(lambdaFn)); } } const app = new cdk.App(); new LambdaCronStack(app, 'LambdaCronExample'); app.synth(); aws-cdk-examples/index.ts at master · aws-samples/aws-cdk-examples https://github.com/aws-samples/aws-cdk-examples/blob/master/typescript/lambda-cron/index.ts
  9. αϯϓϧ$MPVE8BUDI&WFOUTͰىಈ͢Δ-BNCEB'VODUJPO  import events = require('@aws-cdk/aws-events'); import targets = require('@aws-cdk/aws-events-targets');

    import lambda = require('@aws-cdk/aws-lambda'); import cdk = require('@aws-cdk/core'); import fs = require('fs'); export class LambdaCronStack extends cdk.Stack { constructor(app: cdk.App, id: string) { super(app, id); const lambdaFn = new lambda.Function(this, 'Singleton', { code: new lambda.InlineCode(fs.readFileSync('lambda-handler.py', { encoding: 'utf-8' })), handler: 'index.main', timeout: cdk.Duration.seconds(300), runtime: lambda.Runtime.PYTHON_3_6, }); // Run every day at 6PM UTC // See https://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule- expressions.html const rule = new events.Rule(this, 'Rule', { schedule: events.Schedule.expression('cron(0 18 ? * MON-FRI *)') }); rule.addTarget(new targets.LambdaFunction(lambdaFn)); } } const app = new cdk.App(); new LambdaCronStack(app, 'LambdaCronExample'); app.synth(); aws-cdk-examples/index.ts at master · aws-samples/aws-cdk-examples https://github.com/aws-samples/aws-cdk-examples/blob/master/typescript/lambda-cron/index.ts
  10. αϯϓϧ$MPVE8BUDI&WFOUTͰىಈ͢Δ-BNCEB'VODUJPO  import events = require('@aws-cdk/aws-events'); import targets = require('@aws-cdk/aws-events-targets');

    import lambda = require('@aws-cdk/aws-lambda'); import cdk = require('@aws-cdk/core'); import fs = require('fs'); export class LambdaCronStack extends cdk.Stack { constructor(app: cdk.App, id: string) { super(app, id); const lambdaFn = new lambda.Function(this, 'Singleton', { code: new lambda.InlineCode(fs.readFileSync('lambda-handler.py', { encoding: 'utf-8' })), handler: 'index.main', timeout: cdk.Duration.seconds(300), runtime: lambda.Runtime.PYTHON_3_6, }); // Run every day at 6PM UTC // See https://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule- expressions.html const rule = new events.Rule(this, 'Rule', { schedule: events.Schedule.expression('cron(0 18 ? * MON-FRI *)') }); rule.addTarget(new targets.LambdaFunction(lambdaFn)); } } const app = new cdk.App(); new LambdaCronStack(app, 'LambdaCronExample'); app.synth(); aws-cdk-examples/index.ts at master · aws-samples/aws-cdk-examples https://github.com/aws-samples/aws-cdk-examples/blob/master/typescript/lambda-cron/index.ts
  11. αϯϓϧ$MPVE8BUDI&WFOUTͰىಈ͢Δ-BNCEB'VODUJPO  import events = require('@aws-cdk/aws-events'); import targets = require('@aws-cdk/aws-events-targets');

    import lambda = require('@aws-cdk/aws-lambda'); import cdk = require('@aws-cdk/core'); import fs = require('fs'); export class LambdaCronStack extends cdk.Stack { constructor(app: cdk.App, id: string) { super(app, id); const lambdaFn = new lambda.Function(this, 'Singleton', { code: new lambda.InlineCode(fs.readFileSync('lambda-handler.py', { encoding: 'utf-8' })), handler: 'index.main', timeout: cdk.Duration.seconds(300), runtime: lambda.Runtime.PYTHON_3_6, }); // Run every day at 6PM UTC // See https://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule- expressions.html const rule = new events.Rule(this, 'Rule', { schedule: events.Schedule.expression('cron(0 18 ? * MON-FRI *)') }); rule.addTarget(new targets.LambdaFunction(lambdaFn)); } } const app = new cdk.App(); new LambdaCronStack(app, 'LambdaCronExample'); app.synth(); aws-cdk-examples/index.ts at master · aws-samples/aws-cdk-examples https://github.com/aws-samples/aws-cdk-examples/blob/master/typescript/lambda-cron/index.ts - $ cdk deploy - TypeScriptίʔυ͔Β AWS ϦιʔεΛσϓϩΠՄೳ - ཪͰ AWS CloudFormation ςϯϓϨʔτΛੜ੒͍ͯ͠Δ
  12. ߏ੒ྫ  QBDLBHFT NBOBHFNFOUSFBDU MBNCEBOPEF JOGSBBXTDEL QBDLBHFKTPO UTDPOpHCBTFKTPO ./ -

    ֤ workspace Ͱಠཱͯ͠։ൃ͕Մೳ - ಉ࣌ʹɺϓϩδΣΫτϧʔτͷ package.json ͷεΫϦϓτ࣍ୈͰɺ·ͱ ΊͯϏϧυ͢Δ͜ͱ΋Մೳ
  13. -BNCEB'VODUJPOͱ"84$%,ͷ࿈ܞ  "84$%,Ͱ-BNCEB'VODUJPOΛఆٛ͢Δͱ͖ ʹɺϏϧυޙͷ-BNCEB'VODUJPOύεΛࢦఆ͢Ε͹ 0, … new lambda.Function(stack, 'getGreetingReply', {

    functionName: 'getGreetingReply-function', code: lambda.Code.fromAsset(NODE_LAMBDA_SRC_DIR), handler: 'lambda/handlers/api-gw/greeting/api-gw-get-greeting-reply-handler.handler', runtime: lambda.Runtime.NODEJS_12_X, layers: [nodeModulesLayer], environment: { REGION: cdk.Stack.of(stack).region, }, }); …
  14. -BNCEB'VODUJPOͱ"84$%,ͷ࿈ܞ  "84$%,Ͱ-BNCEB'VODUJPOΛఆٛ͢Δͱ͖ ʹɺϏϧυޙͷ-BNCEB'VODUJPOύεΛࢦఆ͢Ε͹ 0, … new lambda.Function(stack, 'getGreetingReply', {

    functionName: 'getGreetingReply-function', code: lambda.Code.fromAsset(NODE_LAMBDA_SRC_DIR), handler: 'lambda/handlers/api-gw/greeting/api-gw-get-greeting-reply-handler.handler', runtime: lambda.Runtime.NODEJS_12_X, layers: [nodeModulesLayer], environment: { REGION: cdk.Stack.of(stack).region, }, }); …
  15. -BNCEB'VODUJPOͱ"84$%,ͷ࿈ܞ  "84$%,Ͱ-BNCEB'VODUJPOΛఆٛ͢Δͱ͖ ʹɺϏϧυޙͷ-BNCEB'VODUJPOύεΛࢦఆ͢Ε͹ 0, … new lambda.Function(stack, 'getGreetingReply', {

    functionName: 'getGreetingReply-function', code: lambda.Code.fromAsset(NODE_LAMBDA_SRC_DIR), handler: 'lambda/handlers/api-gw/greeting/api-gw-get-greeting-reply-handler.handler', runtime: lambda.Runtime.NODEJS_12_X, layers: [nodeModulesLayer], environment: { REGION: cdk.Stack.of(stack).region, }, }); … - $ yarn deploy
  16. ؀ڥ͝ͱʹσϓϩΠͰ͖ΔΑ͏ʹ͓ͯ͘͠  ελοΫ໊Λ؀ڥ͝ͱʹม͑Δ͜ͱͰରԠՄೳ ؀ڥม਺ͳͲʹೖΕ͓ͯ͘ͱྑ͍ export async function greetingApplicationStack( scope: cdk.Construct,

    id: string, global: GlobalProps, ): Promise<Stack> { // dev | stg | prd const stage = process.env.STAGE_NAME!; const stack = new cdk.Stack(scope, id, { stackName: `${stage}-${id}-stack`, }); const buckets = await s3Construct.reference(stack, bucketArns); const dynamoTables = await dynamoConstruct.reference(stack, dynamoArns); const nodeModulesLayer = cdkLambda.LayerVersion.fromLayerVersionArn( stack, 'NodeModulesLayer', nodeModulesLayerArn, ); // lambda const lambda = await greetingLambdaConstruct(stack, global, { buckets,dynamoTables,nodeModulesLayer, }); // API Gateway await greetingApiConstruct(stack, global, { lambda, env: { apiStageName: 'v1'}, }); return stack; }
  17. ؀ڥ͝ͱʹσϓϩΠͰ͖ΔΑ͏ʹ͓ͯ͘͠  ελοΫ໊Λ؀ڥ͝ͱʹม͑Δ͜ͱͰରԠՄೳ ؀ڥม਺ͳͲʹೖΕ͓ͯ͘ͱྑ͍ export async function greetingApplicationStack( scope: cdk.Construct,

    id: string, global: GlobalProps, ): Promise<Stack> { // dev | stg | prd const stage = process.env.STAGE_NAME!; const stack = new cdk.Stack(scope, id, { stackName: `${stage}-${id}-stack`, }); const buckets = await s3Construct.reference(stack, bucketArns); const dynamoTables = await dynamoConstruct.reference(stack, dynamoArns); const nodeModulesLayer = cdkLambda.LayerVersion.fromLayerVersionArn( stack, 'NodeModulesLayer', nodeModulesLayerArn, ); // lambda const lambda = await greetingLambdaConstruct(stack, global, { buckets,dynamoTables,nodeModulesLayer, }); // API Gateway await greetingApiConstruct(stack, global, { lambda, env: { apiStageName: 'v1'}, }); return stack; }
  18. ΋ͪΖΜ"84$PEF1JQFMJOFͷߏங΋"84$%,Ͱ  const applicationBuild = new codeBuild.PipelineProject( stack, 'GreetingApplicationDeploy-project', {

    projectName: 'GreetinApplicationDeploy-project', buildSpec: codeBuild.BuildSpec.fromSourceFilename( './buildspec/buildspec-deploy.yml', ), role: deployRole, environment: { buildImage: LinuxBuildImage.STANDARD_3_0, environmentVariables: { AWS_DEFAULT_REGION: { type: codeBuild.BuildEnvironmentVariableType.PLAINTEXT, value: stack.region, }, }, }, }, );
  19. "84"QQ4ZODʹΑΔ#BDLFOEGPS'SPOUFOE  const graphApi = new appsync.GraphQLApi(stack, 'AdminBff', { name:

    global.getGraphApiName('AdminBff'), authorizationConfig: { defaultAuthorization: { authorizationType: AuthorizationType.API_KEY, apiKeyConfig: { description: 'test api key config', expires: luxon.DateTime.local().plus({ days: 7 }).toISO(), name: 'default test api key', }, }, additionalAuthorizationModes: [], }, logConfig: { fieldLogLevel: FieldLogLevel.ALL, excludeVerboseContent: true, }, schemaDefinitionFile: path.join(__dirname, 'schema.graphql'), });
  20. "84"QQ4ZODʹΑΔ#BDLFOEGPS'SPOUFOE  const graphApi = new appsync.GraphQLApi(stack, 'AdminBff', { name:

    global.getGraphApiName('AdminBff'), authorizationConfig: { defaultAuthorization: { authorizationType: AuthorizationType.API_KEY, apiKeyConfig: { description: 'test api key config', expires: luxon.DateTime.local().plus({ days: 7 }).toISO(), name: 'default test api key', }, }, additionalAuthorizationModes: [], }, logConfig: { fieldLogLevel: FieldLogLevel.ALL, excludeVerboseContent: true, }, schemaDefinitionFile: path.join(__dirname, 'schema.graphql'), });
  21. "84"QQ4ZODʹΑΔ#BDLFOEGPS'SPOUFOE  const greetingTableDataSource = graphApi.addDynamoDbDataSource( 'GreetingTableDataSource', 'greeting table', dynamoTables.greetingTable,

    ); greetingTableDataSource.createResolver({ typeName: 'Mutation', fieldName: 'createHello', requestMappingTemplate: MappingTemplate.dynamoDbPutItem( PrimaryKey.partition('id').auto(), Values.projecting('input'), ), responseMappingTemplate: MappingTemplate.dynamoDbResultItem(), });
  22. "84"QQ4ZODʹΑΔ#BDLFOEGPS'SPOUFOE  const greetingTableDataSource = graphApi.addDynamoDbDataSource( 'GreetingTableDataSource', 'greeting table', dynamoTables.greetingTable,

    ); greetingTableDataSource.createResolver({ typeName: 'Mutation', fieldName: 'createHello', requestMappingTemplate: MappingTemplate.dynamoDbPutItem( PrimaryKey.partition('id').auto(), Values.projecting('input'), ), responseMappingTemplate: MappingTemplate.dynamoDbResultItem(), }); (SBQI"QJʹ %BUB4PVSDFΛ௥Ճ
  23. "84"QQ4ZODʹΑΔ#BDLFOEGPS'SPOUFOE  const greetingTableDataSource = graphApi.addDynamoDbDataSource( 'GreetingTableDataSource', 'greeting table', dynamoTables.greetingTable,

    ); greetingTableDataSource.createResolver({ typeName: 'Mutation', fieldName: 'createHello', requestMappingTemplate: MappingTemplate.dynamoDbPutItem( PrimaryKey.partition('id').auto(), Values.projecting('input'), ), responseMappingTemplate: MappingTemplate.dynamoDbResultItem(), }); %BUB4PVSDFʹ 3FTPMWFSΛ௥Ճ
  24. "84$%,"1*(BUFXBZߏங෦෼  const api = new apig.RestApi(scope, 'GreetingApi', { restApiName:

    global.getApiName('Greeting'), endpointTypes: [apig.EndpointType.REGIONAL], deployOptions: { stageName:’v1’, }, }); const helloLink = new VpcLink(scope, 'VpcLink', { targets: [ NetworkLoadBalancer.fromNetworkLoadBalancerAttributes( scope, ‘GreetingNlb', { loadBalancerArn: ‘arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxx:loadbalancer/net/Bonjo-Ec2Se-xfsda/12234567890', }, ), ], }); const helloResource = api.root.addResource('helo'); helloResource.addMethod( 'GET', new apig.Integration({ type: IntegrationType.HTTP_PROXY, integrationHttpMethod: ‘GET', url: ‘http://abxyfskeladk.elb.ap-northeast-1.amazonaws.com’, options: { connectionType: ConnectionType.VPC_LINK, vpcLink: helloLink, }, }), { methodResponses: [{statusCode: ‘200'}] },
  25. "84$%,"1*(BUFXBZߏங෦෼  const api = new apig.RestApi(scope, 'GreetingApi', { restApiName:

    global.getApiName('Greeting'), endpointTypes: [apig.EndpointType.REGIONAL], deployOptions: { stageName:’v1’, }, }); const helloLink = new VpcLink(scope, 'VpcLink', { targets: [ NetworkLoadBalancer.fromNetworkLoadBalancerAttributes( scope, ‘GreetingNlb', { loadBalancerArn: ‘arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxx:loadbalancer/net/Bonjo-Ec2Se-xfsda/12234567890', }, ), ], }); const helloResource = api.root.addResource('helo'); helloResource.addMethod( 'GET', new apig.Integration({ type: IntegrationType.HTTP_PROXY, integrationHttpMethod: ‘GET', url: ‘http://abxyfskeladk.elb.ap-northeast-1.amazonaws.com’, options: { connectionType: ConnectionType.VPC_LINK, vpcLink: helloLink, }, }), { methodResponses: [{statusCode: ‘200'}] }, طଘ/-#ΑΓ 71$-JOL࡞੒
  26. "84$%,"1*(BUFXBZߏங෦෼  const api = new apig.RestApi(scope, 'GreetingApi', { restApiName:

    global.getApiName('Greeting'), endpointTypes: [apig.EndpointType.REGIONAL], deployOptions: { stageName:’v1’, }, }); const helloLink = new VpcLink(scope, 'VpcLink', { targets: [ NetworkLoadBalancer.fromNetworkLoadBalancerAttributes( scope, ‘GreetingNlb', { loadBalancerArn: ‘arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxx:loadbalancer/net/Bonjo-Ec2Se-xfsda/12234567890', }, ), ], }); const helloResource = api.root.addResource('helo'); helloResource.addMethod( 'GET', new apig.Integration({ type: IntegrationType.HTTP_PROXY, integrationHttpMethod: ‘GET', url: ‘http://abxyfskeladk.elb.ap-northeast-1.amazonaws.com’, options: { connectionType: ConnectionType.VPC_LINK, vpcLink: helloLink, }, }), { methodResponses: [{statusCode: ‘200'}] }, "1*(BUFXBZͱ 71$-JOLΛ઀ଓ
  27. "84$%,ͳΒ4UBUF.BDIJOFΛϝιουͰ਺चͭͳ͗ʹ  const convertCsvTask = new sfnTasks.LambdaInvoke( stack, 'CsvConvertTask', {

    lambdaFunction: lambda.convertCsvToJsonLinesFn, invocationType: LambdaInvocationType.REQUEST_RESPONSE, resultPath: '$.convert', }, ); const waitForConvert = new sfn.Wait(stack, 'WaitForConvert', { time: sfn.WaitTime.duration(Duration.seconds(5)), }); const writeDynamodbTask = new sfnTasks.LambdaInvoke( stack, 'WriteDynamodbTask', { lambdaFunction: lambda.writeDynamodbFn, invocationType: LambdaInvocationType.REQUEST_RESPONSE, resultPath: '$.writeData', inputPath: '$.convert.Payload', }, ); const batchWriteChain = sfn.Chain.start(convertCsvTask) .next(waitForConvert) .next(writeDynamodbTask) const batchWriteMachine = new sfn.StateMachine(stack, 'BatchWriteMachine', { stateMachineName: global.getStateMachineName('BatchWriteMachine'), definition: chain, timeout: cdk.Duration.minutes(20), });
  28. const convertCsvTask = new sfnTasks.LambdaInvoke( stack, 'CsvConvertTask', { lambdaFunction: lambda.convertCsvToJsonLinesFn,

    invocationType: LambdaInvocationType.REQUEST_RESPONSE, resultPath: '$.convert', }, ); const waitForConvert = new sfn.Wait(stack, 'WaitForConvert', { time: sfn.WaitTime.duration(Duration.seconds(5)), }); const writeDynamodbTask = new sfnTasks.LambdaInvoke( stack, 'WriteDynamodbTask', { lambdaFunction: lambda.writeDynamodbFn, invocationType: LambdaInvocationType.REQUEST_RESPONSE, resultPath: '$.writeData', inputPath: '$.convert.Payload', }, ); const batchWriteChain = sfn.Chain.start(convertCsvTask) .next(waitForConvert) .next(writeDynamodbTask) const batchWriteMachine = new sfn.StateMachine(stack, 'BatchWriteMachine', { stateMachineName: global.getStateMachineName('BatchWriteMachine'), definition: chain, timeout: cdk.Duration.minutes(20), }); "84$%,ͳΒ4UBUF.BDIJOFΛϝιουͰ਺चͭͳ͗ʹ