Skip to content

Commit a1fbd51

Browse files
authored
fix(stepfunctions): the retry field in CustomState is not iterable (#29403)
### Issue # (if applicable) Closes #29274 ### Reason for this change CDK users were unable to specify their retry strategy if it was specified inline in their ASL state machine definition ### Description of changes Checks if the state definition has an inline retry policy defined. If it does, add it to the existing strategy defined using `addRetry` (if there is one defined, this is where it was failing before) ### Description of how you validated changes Added unit and integration 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 0c73143 commit a1fbd51

File tree

7 files changed

+87
-8
lines changed

7 files changed

+87
-8
lines changed

packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/aws-stepfunctions-custom-state-integ.assets.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.custom-state.js.snapshot/aws-stepfunctions-custom-state-integ.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 custom task\",\"States\":{\"my custom task\":{\"Next\":\"final step\",\"Type\":\"Task\",\"Resource\":\"arn:aws:states:::dynamodb:putItem\",\"Parameters\":{\"TableName\":\"my-cool-table\",\"Item\":{\"id\":{\"S\":\"my-entry\"}}},\"ResultPath\":null,\"Retry\":[{\"ErrorEquals\":[\"States.Timeout\"],\"IntervalSeconds\":10,\"MaxAttempts\":5},{\"ErrorEquals\":[\"States.Permissions\"],\"IntervalSeconds\":20,\"MaxAttempts\":2}],\"Catch\":[{\"ErrorEquals\":[\"States.ALL\"],\"Next\":\"failed\"}]},\"final step\":{\"Type\":\"Pass\",\"End\":true},\"failed\":{\"Type\":\"Fail\",\"Error\":\"DidNotWork\",\"Cause\":\"We got stuck\"}},\"TimeoutSeconds\":30}",
23+
"DefinitionString": "{\"StartAt\":\"my custom task\",\"States\":{\"my custom task\":{\"Next\":\"my custom task with inline Retriers\",\"Type\":\"Task\",\"Resource\":\"arn:aws:states:::dynamodb:putItem\",\"Parameters\":{\"TableName\":\"my-cool-table\",\"Item\":{\"id\":{\"S\":\"my-entry\"}}},\"ResultPath\":null,\"Retry\":[{\"ErrorEquals\":[\"States.Timeout\"],\"IntervalSeconds\":10,\"MaxAttempts\":5},{\"ErrorEquals\":[\"States.Permissions\"],\"IntervalSeconds\":20,\"MaxAttempts\":2}],\"Catch\":[{\"ErrorEquals\":[\"States.ALL\"],\"Next\":\"failed\"}]},\"my custom task with inline Retriers\":{\"Next\":\"final step\",\"Type\":\"Task\",\"Resource\":\"arn:aws:states:::dynamodb:putItem\",\"Parameters\":{\"TableName\":\"my-cool-table\",\"Item\":{\"id\":{\"S\":\"my-entry\"}}},\"ResultPath\":null,\"Retry\":[{\"ErrorEquals\":[\"States.Permissions\"],\"IntervalSeconds\":20,\"MaxAttempts\":2}]},\"final step\":{\"Type\":\"Pass\",\"End\":true},\"failed\":{\"Type\":\"Fail\",\"Error\":\"DidNotWork\",\"Cause\":\"We got stuck\"}},\"TimeoutSeconds\":30}",
2424
"RoleArn": {
2525
"Fn::GetAtt": [
2626
"StateMachineRoleB840431D",

packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/manifest.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.custom-state.js.snapshot/tree.json

+9-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.custom-state.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,18 @@ const custom = new sfn.CustomState(stack, 'my custom task', {
3939
stateJson,
4040
});
4141

42+
const customWithInlineRetry = new sfn.CustomState(stack, 'my custom task with inline Retriers', {
43+
stateJson,
44+
});
45+
4246
custom.addCatch(failure);
4347
custom.addRetry({
4448
errors: [sfn.Errors.TIMEOUT],
4549
interval: cdk.Duration.seconds(10),
4650
maxAttempts: 5,
4751
});
4852

49-
const chain = sfn.Chain.start(custom).next(finalStatus);
53+
const chain = sfn.Chain.start(custom).next(customWithInlineRetry).next(finalStatus);
5054

5155
const sm = new sfn.StateMachine(stack, 'StateMachine', {
5256
definition: chain,

packages/aws-cdk-lib/aws-stepfunctions/lib/states/custom-state.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ export class CustomState extends State implements IChainable, INextable {
7474
...this.renderRetryCatch(),
7575
};
7676

77-
// merge the Retry filed defined in the stateJson into the state
77+
// merge the Retry field defined in the stateJson into the state
7878
if (Array.isArray(this.stateJson.Retry)) {
79-
state.Retry = [...state.Retry, ...this.stateJson.Retry];
79+
state.Retry = Array.isArray(state.Retry) ? [...state.Retry, ...this.stateJson.Retry] : [...this.stateJson.Retry];
8080
}
8181

8282
return state;

packages/aws-cdk-lib/aws-stepfunctions/test/custom-state.test.ts

+67
Original file line numberDiff line numberDiff line change
@@ -242,4 +242,71 @@ describe('Custom State', () => {
242242
},
243243
);
244244
});
245+
246+
test('expect retry to not fail when specifying strategy inline', () => {
247+
// GIVEN
248+
const custom = new sfn.CustomState(stack, 'Custom', {
249+
stateJson: {
250+
Type: 'Task',
251+
Resource: 'arn:aws:states:::dynamodb:putItem',
252+
Parameters: {
253+
TableName: 'MyTable',
254+
Item: {
255+
id: {
256+
S: 'MyEntry',
257+
},
258+
},
259+
},
260+
ResultPath: null,
261+
Retry: [
262+
{
263+
ErrorEquals: [
264+
'Lambda.ServiceException',
265+
'Lambda.AWSLambdaException',
266+
'Lambda.SdkClientException',
267+
'Lambda.TooManyRequestsException',
268+
],
269+
IntervalSeconds: 20,
270+
MaxAttempts: 2,
271+
},
272+
],
273+
},
274+
});
275+
const chain = sfn.Chain.start(custom);
276+
277+
// THEN
278+
expect(render(stack, chain)).toStrictEqual(
279+
{
280+
StartAt: 'Custom',
281+
States: {
282+
Custom: {
283+
Type: 'Task',
284+
Resource: 'arn:aws:states:::dynamodb:putItem',
285+
Parameters: {
286+
TableName: 'MyTable',
287+
Item: {
288+
id: {
289+
S: 'MyEntry',
290+
},
291+
},
292+
},
293+
ResultPath: null,
294+
Retry: [
295+
{
296+
ErrorEquals: [
297+
'Lambda.ServiceException',
298+
'Lambda.AWSLambdaException',
299+
'Lambda.SdkClientException',
300+
'Lambda.TooManyRequestsException',
301+
],
302+
IntervalSeconds: 20,
303+
MaxAttempts: 2,
304+
},
305+
],
306+
End: true,
307+
},
308+
},
309+
},
310+
);
311+
});
245312
});

0 commit comments

Comments
 (0)