diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk-stepfunctions-map-distributed-stack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk-stepfunctions-map-distributed-stack.assets.json index a71a5fd674bd0..c2d9506a6a2a5 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk-stepfunctions-map-distributed-stack.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk-stepfunctions-map-distributed-stack.assets.json @@ -1,7 +1,7 @@ { - "version": "34.0.0", + "version": "36.0.0", "files": { - "9947de492887a96f39e8510bfffd6b8914e1677fe0dab27eb0c043f0c2f6d17a": { + "02a90dd088b90a83c2e917a07e465b621f46664f62ae3c4440f0d0799957e3f4": { "source": { "path": "cdk-stepfunctions-map-distributed-stack.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "9947de492887a96f39e8510bfffd6b8914e1677fe0dab27eb0c043f0c2f6d17a.json", + "objectKey": "02a90dd088b90a83c2e917a07e465b621f46664f62ae3c4440f0d0799957e3f4.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk-stepfunctions-map-distributed-stack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk-stepfunctions-map-distributed-stack.template.json index 0dbcc08458793..ca6011ed5094a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk-stepfunctions-map-distributed-stack.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk-stepfunctions-map-distributed-stack.template.json @@ -20,7 +20,7 @@ "StateMachine2E01A3A5": { "Type": "AWS::StepFunctions::StateMachine", "Properties": { - "DefinitionString": "{\"StartAt\":\"My-Map-State\",\"States\":{\"My-Map-State\":{\"Type\":\"Map\",\"End\":true,\"Parameters\":{\"foo\":\"foo\",\"bar.$\":\"$.bar\"},\"ItemsPath\":\"$.inputForMap\",\"ItemProcessor\":{\"ProcessorConfig\":{\"Mode\":\"DISTRIBUTED\",\"ExecutionType\":\"STANDARD\"},\"StartAt\":\"Pass State\",\"States\":{\"Pass State\":{\"Type\":\"Pass\",\"End\":true}}},\"MaxConcurrency\":1}},\"TimeoutSeconds\":30}", + "DefinitionString": "{\"StartAt\":\"My-Map-State\",\"States\":{\"My-Map-State\":{\"Type\":\"Map\",\"End\":true,\"Parameters\":{\"foo\":\"foo\",\"bar.$\":\"$.bar\"},\"ItemsPath\":\"$.inputForMap\",\"ItemProcessor\":{\"ProcessorConfig\":{\"Mode\":\"DISTRIBUTED\",\"ExecutionType\":\"STANDARD\"},\"StartAt\":\"Pass State\",\"States\":{\"Pass State\":{\"Type\":\"Pass\",\"End\":true}}},\"MaxConcurrencyPath\":\"$.maxConcurrency\"}},\"TimeoutSeconds\":30}", "RoleArn": { "Fn::GetAtt": [ "StateMachineRoleB840431D", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk.out index 2313ab5436501..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"34.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdkstepfunctionsmapdistributedintegDefaultTestDeployAssert69F30423.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdkstepfunctionsmapdistributedintegDefaultTestDeployAssert69F30423.assets.json index 4ea723044a871..173182173d32c 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdkstepfunctionsmapdistributedintegDefaultTestDeployAssert69F30423.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdkstepfunctionsmapdistributedintegDefaultTestDeployAssert69F30423.assets.json @@ -1,5 +1,5 @@ { - "version": "34.0.0", + "version": "36.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/integ.json index 49c5aed19a1c4..cd3346dd3eb6c 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "34.0.0", + "version": "36.0.0", "testCases": { "cdk-stepfunctions-map-distributed-integ/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/manifest.json index 1dead0f510155..d0bedf2d3a6b0 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "34.0.0", + "version": "36.0.0", "artifacts": { "cdk-stepfunctions-map-distributed-stack.assets": { "type": "cdk:asset-manifest", @@ -18,7 +18,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/9947de492887a96f39e8510bfffd6b8914e1677fe0dab27eb0c043f0c2f6d17a.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/02a90dd088b90a83c2e917a07e465b621f46664f62ae3c4440f0d0799957e3f4.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/tree.json index ed58194eadb4f..fa970c0ce7496 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/tree.json @@ -77,7 +77,7 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::StepFunctions::StateMachine", "aws:cdk:cloudformation:props": { - "definitionString": "{\"StartAt\":\"My-Map-State\",\"States\":{\"My-Map-State\":{\"Type\":\"Map\",\"End\":true,\"Parameters\":{\"foo\":\"foo\",\"bar.$\":\"$.bar\"},\"ItemsPath\":\"$.inputForMap\",\"ItemProcessor\":{\"ProcessorConfig\":{\"Mode\":\"DISTRIBUTED\",\"ExecutionType\":\"STANDARD\"},\"StartAt\":\"Pass State\",\"States\":{\"Pass State\":{\"Type\":\"Pass\",\"End\":true}}},\"MaxConcurrency\":1}},\"TimeoutSeconds\":30}", + "definitionString": "{\"StartAt\":\"My-Map-State\",\"States\":{\"My-Map-State\":{\"Type\":\"Map\",\"End\":true,\"Parameters\":{\"foo\":\"foo\",\"bar.$\":\"$.bar\"},\"ItemsPath\":\"$.inputForMap\",\"ItemProcessor\":{\"ProcessorConfig\":{\"Mode\":\"DISTRIBUTED\",\"ExecutionType\":\"STANDARD\"},\"StartAt\":\"Pass State\",\"States\":{\"Pass State\":{\"Type\":\"Pass\",\"End\":true}}},\"MaxConcurrencyPath\":\"$.maxConcurrency\"}},\"TimeoutSeconds\":30}", "roleArn": { "Fn::GetAtt": [ "StateMachineRoleB840431D", @@ -140,7 +140,7 @@ "path": "cdk-stepfunctions-map-distributed-integ/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.70" + "version": "10.3.0" } }, "DeployAssert": { @@ -186,7 +186,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.70" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.ts index bb99002f11e69..66f3a38fd6114 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.ts @@ -12,7 +12,7 @@ const stack = new cdk.Stack(app, 'cdk-stepfunctions-map-distributed-stack'); const map = new sfn.Map(stack, 'Map', { stateName: 'My-Map-State', - maxConcurrency: 1, + maxConcurrencyPath: sfn.JsonPath.stringAt('$.maxConcurrency'), itemsPath: sfn.JsonPath.stringAt('$.inputForMap'), parameters: { foo: 'foo', diff --git a/packages/aws-cdk-lib/aws-stepfunctions/lib/states/map-base.ts b/packages/aws-cdk-lib/aws-stepfunctions/lib/states/map-base.ts index 95e8532a64375..2359558b33624 100644 --- a/packages/aws-cdk-lib/aws-stepfunctions/lib/states/map-base.ts +++ b/packages/aws-cdk-lib/aws-stepfunctions/lib/states/map-base.ts @@ -90,9 +90,24 @@ export interface MapBaseProps { * * An upper bound on the number of iterations you want running at once. * + * @see + * https://docs.aws.amazon.com/step-functions/latest/dg/concepts-asl-use-map-state-inline.html#map-state-inline-additional-fields + * * @default - full concurrency */ readonly maxConcurrency?: number; + + /** + * MaxConcurrencyPath + * + * A JsonPath that specifies the maximum concurrency dynamically from the state input. + * + * @see + * https://docs.aws.amazon.com/step-functions/latest/dg/concepts-asl-use-map-state-inline.html#map-state-inline-additional-fields + * + * @default - full concurrency + */ + readonly maxConcurrencyPath?: string; } /** @@ -122,6 +137,7 @@ export abstract class MapBase extends State implements INextable { public readonly endStates: INextable[]; private readonly maxConcurrency?: number; + private readonly maxConcurrencyPath?: string; protected readonly itemsPath?: string; protected readonly itemSelector?: { [key: string]: any }; @@ -129,6 +145,7 @@ export abstract class MapBase extends State implements INextable { super(scope, id, props); this.endStates = [this]; this.maxConcurrency = props.maxConcurrency; + this.maxConcurrencyPath = props.maxConcurrencyPath; this.itemsPath = props.itemsPath; this.itemSelector = props.itemSelector; } @@ -156,7 +173,8 @@ export abstract class MapBase extends State implements INextable { ...this.renderItemsPath(), ...this.renderItemSelector(), ...this.renderItemProcessor(), - MaxConcurrency: this.maxConcurrency, + ...(this.maxConcurrency && { MaxConcurrency: this.maxConcurrency }), + ...(this.maxConcurrencyPath && { MaxConcurrencyPath: renderJsonPath(this.maxConcurrencyPath) }), }; } @@ -174,6 +192,10 @@ export abstract class MapBase extends State implements INextable { errors.push('maxConcurrency has to be a positive integer'); } + if (this.maxConcurrency && this.maxConcurrencyPath) { + errors.push('Provide either `maxConcurrency` or `maxConcurrencyPath`, but not both'); + } + return errors; } diff --git a/packages/aws-cdk-lib/aws-stepfunctions/test/map.test.ts b/packages/aws-cdk-lib/aws-stepfunctions/test/map.test.ts index a082bf1bea61f..be09ab9282609 100644 --- a/packages/aws-cdk-lib/aws-stepfunctions/test/map.test.ts +++ b/packages/aws-cdk-lib/aws-stepfunctions/test/map.test.ts @@ -45,6 +45,49 @@ describe('Map State', () => { }); }), + test('State Machine With Map State and MaxConcurrencyPath', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + const map = new stepfunctions.Map(stack, 'Map State', { + stateName: 'My-Map-State', + maxConcurrencyPath: stepfunctions.JsonPath.stringAt('$.maxConcurrencyPath'), + itemsPath: stepfunctions.JsonPath.stringAt('$.inputForMap'), + parameters: { + foo: 'foo', + bar: stepfunctions.JsonPath.stringAt('$.bar'), + }, + }); + map.iterator(new stepfunctions.Pass(stack, 'Pass State')); + + // THEN + expect(render(map)).toStrictEqual({ + StartAt: 'My-Map-State', + States: { + 'My-Map-State': { + Type: 'Map', + End: true, + Parameters: { + 'foo': 'foo', + 'bar.$': '$.bar', + }, + Iterator: { + StartAt: 'Pass State', + States: { + 'Pass State': { + Type: 'Pass', + End: true, + }, + }, + }, + ItemsPath: '$.inputForMap', + MaxConcurrencyPath: '$.maxConcurrencyPath', + }, + }, + }); + }), + test('State Machine With Map State and ResultSelector', () => { // GIVEN const stack = new cdk.Stack(); @@ -395,6 +438,21 @@ describe('Map State', () => { expect(() => app.synth()).toThrow(/maxConcurrency has to be a positive integer/); }), + test('fails in synthesis when maxConcurrency and maxConcurrencyPath are both defined', () => { + const app = createAppWithMap((stack) => { + const map = new stepfunctions.Map(stack, 'Map State', { + maxConcurrency: 1, + maxConcurrencyPath: stepfunctions.JsonPath.stringAt('$.maxConcurrencyPath'), + itemsPath: stepfunctions.JsonPath.stringAt('$.inputForMap'), + }); + map.iterator(new stepfunctions.Pass(stack, 'Pass State')); + + return map; + }); + + expect(() => app.synth()).toThrow(/Provide either `maxConcurrency` or `maxConcurrencyPath`, but not both/); + }), + test('does not fail synthesis when maxConcurrency is a jsonPath', () => { const app = createAppWithMap((stack) => { const map = new stepfunctions.Map(stack, 'Map State', {