Skip to content

Commit b19f822

Browse files
authored
fix(stepfunctions): maxConcurrency does not support JsonPath (#29330)
### Issue # (if applicable) Relates to #20835 ### Reason for this change `MaxConcurrency` does not support `JsonPath`. This change adds `MaxConcurrencyPath` so that CDK users can specify a `JsonPath` for their `MaxConcurrency` _Note_ : This does not invalidate JsonPaths for `MaxConcurrency`, as I'm unsure how to do so without reverting #20279 . Open to suggestions ### Description of changes Added a new `maxConcurrencyPath` field that accepts a `JsonPath` value. Decided to go with another explicit field as it is similar to what is done for `ErrorPath` and `CausePath`, in addition to most other Path fields ### Description of how you validated changes Added unit tests ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent c9d8add commit b19f822

File tree

10 files changed

+94
-14
lines changed

10 files changed

+94
-14
lines changed

packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk-stepfunctions-map-distributed-stack.assets.json

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk-stepfunctions-map-distributed-stack.template.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"StateMachine2E01A3A5": {
2121
"Type": "AWS::StepFunctions::StateMachine",
2222
"Properties": {
23-
"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}",
23+
"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}",
2424
"RoleArn": {
2525
"Fn::GetAtt": [
2626
"StateMachineRoleB840431D",

packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdk.out

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/cdkstepfunctionsmapdistributedintegDefaultTestDeployAssert69F30423.assets.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/integ.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/manifest.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.js.snapshot/tree.json

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.map-distributed.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const stack = new cdk.Stack(app, 'cdk-stepfunctions-map-distributed-stack');
1212

1313
const map = new sfn.Map(stack, 'Map', {
1414
stateName: 'My-Map-State',
15-
maxConcurrency: 1,
15+
maxConcurrencyPath: sfn.JsonPath.stringAt('$.maxConcurrency'),
1616
itemsPath: sfn.JsonPath.stringAt('$.inputForMap'),
1717
parameters: {
1818
foo: 'foo',

packages/aws-cdk-lib/aws-stepfunctions/lib/states/map-base.ts

+23-1
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,24 @@ export interface MapBaseProps {
9090
*
9191
* An upper bound on the number of iterations you want running at once.
9292
*
93+
* @see
94+
* https://docs.aws.amazon.com/step-functions/latest/dg/concepts-asl-use-map-state-inline.html#map-state-inline-additional-fields
95+
*
9396
* @default - full concurrency
9497
*/
9598
readonly maxConcurrency?: number;
99+
100+
/**
101+
* MaxConcurrencyPath
102+
*
103+
* A JsonPath that specifies the maximum concurrency dynamically from the state input.
104+
*
105+
* @see
106+
* https://docs.aws.amazon.com/step-functions/latest/dg/concepts-asl-use-map-state-inline.html#map-state-inline-additional-fields
107+
*
108+
* @default - full concurrency
109+
*/
110+
readonly maxConcurrencyPath?: string;
96111
}
97112

98113
/**
@@ -122,13 +137,15 @@ export abstract class MapBase extends State implements INextable {
122137
public readonly endStates: INextable[];
123138

124139
private readonly maxConcurrency?: number;
140+
private readonly maxConcurrencyPath?: string;
125141
protected readonly itemsPath?: string;
126142
protected readonly itemSelector?: { [key: string]: any };
127143

128144
constructor(scope: Construct, id: string, props: MapBaseProps = {}) {
129145
super(scope, id, props);
130146
this.endStates = [this];
131147
this.maxConcurrency = props.maxConcurrency;
148+
this.maxConcurrencyPath = props.maxConcurrencyPath;
132149
this.itemsPath = props.itemsPath;
133150
this.itemSelector = props.itemSelector;
134151
}
@@ -156,7 +173,8 @@ export abstract class MapBase extends State implements INextable {
156173
...this.renderItemsPath(),
157174
...this.renderItemSelector(),
158175
...this.renderItemProcessor(),
159-
MaxConcurrency: this.maxConcurrency,
176+
...(this.maxConcurrency && { MaxConcurrency: this.maxConcurrency }),
177+
...(this.maxConcurrencyPath && { MaxConcurrencyPath: renderJsonPath(this.maxConcurrencyPath) }),
160178
};
161179
}
162180

@@ -174,6 +192,10 @@ export abstract class MapBase extends State implements INextable {
174192
errors.push('maxConcurrency has to be a positive integer');
175193
}
176194

195+
if (this.maxConcurrency && this.maxConcurrencyPath) {
196+
errors.push('Provide either `maxConcurrency` or `maxConcurrencyPath`, but not both');
197+
}
198+
177199
return errors;
178200
}
179201

packages/aws-cdk-lib/aws-stepfunctions/test/map.test.ts

+58
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,49 @@ describe('Map State', () => {
4545
});
4646
}),
4747

48+
test('State Machine With Map State and MaxConcurrencyPath', () => {
49+
// GIVEN
50+
const stack = new cdk.Stack();
51+
52+
// WHEN
53+
const map = new stepfunctions.Map(stack, 'Map State', {
54+
stateName: 'My-Map-State',
55+
maxConcurrencyPath: stepfunctions.JsonPath.stringAt('$.maxConcurrencyPath'),
56+
itemsPath: stepfunctions.JsonPath.stringAt('$.inputForMap'),
57+
parameters: {
58+
foo: 'foo',
59+
bar: stepfunctions.JsonPath.stringAt('$.bar'),
60+
},
61+
});
62+
map.iterator(new stepfunctions.Pass(stack, 'Pass State'));
63+
64+
// THEN
65+
expect(render(map)).toStrictEqual({
66+
StartAt: 'My-Map-State',
67+
States: {
68+
'My-Map-State': {
69+
Type: 'Map',
70+
End: true,
71+
Parameters: {
72+
'foo': 'foo',
73+
'bar.$': '$.bar',
74+
},
75+
Iterator: {
76+
StartAt: 'Pass State',
77+
States: {
78+
'Pass State': {
79+
Type: 'Pass',
80+
End: true,
81+
},
82+
},
83+
},
84+
ItemsPath: '$.inputForMap',
85+
MaxConcurrencyPath: '$.maxConcurrencyPath',
86+
},
87+
},
88+
});
89+
}),
90+
4891
test('State Machine With Map State and ResultSelector', () => {
4992
// GIVEN
5093
const stack = new cdk.Stack();
@@ -395,6 +438,21 @@ describe('Map State', () => {
395438
expect(() => app.synth()).toThrow(/maxConcurrency has to be a positive integer/);
396439
}),
397440

441+
test('fails in synthesis when maxConcurrency and maxConcurrencyPath are both defined', () => {
442+
const app = createAppWithMap((stack) => {
443+
const map = new stepfunctions.Map(stack, 'Map State', {
444+
maxConcurrency: 1,
445+
maxConcurrencyPath: stepfunctions.JsonPath.stringAt('$.maxConcurrencyPath'),
446+
itemsPath: stepfunctions.JsonPath.stringAt('$.inputForMap'),
447+
});
448+
map.iterator(new stepfunctions.Pass(stack, 'Pass State'));
449+
450+
return map;
451+
});
452+
453+
expect(() => app.synth()).toThrow(/Provide either `maxConcurrency` or `maxConcurrencyPath`, but not both/);
454+
}),
455+
398456
test('does not fail synthesis when maxConcurrency is a jsonPath', () => {
399457
const app = createAppWithMap((stack) => {
400458
const map = new stepfunctions.Map(stack, 'Map State', {

0 commit comments

Comments
 (0)