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..1f14c1377715d 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 @@ -93,6 +93,15 @@ export interface MapBaseProps { * @default - full concurrency */ readonly maxConcurrency?: number; + + /** + * MaxConcurrencyPath + * + * An upper bound on the number of iterations you want running at once, in JsonPath. + * + * @default - full concurrency + */ + readonly maxConcurrencyPath?: string; } /** @@ -122,6 +131,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 +139,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 +167,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 +186,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', {