Skip to content

Commit 3c33e2c

Browse files
authored
fix(stepfunctions): the Retry field in the statesJson in CustomState is always overwrited (#28793)
After #28422 was merged, the regression that overwrites the Retry field defined in the stateJson was introduced. The `this.renderRetryCatch()` method overwrites the Retry field in the stateJson. https://github.com/aws/aws-cdk/blob/45b8398bec9ba9c03f195c14f3b92188c9058a7b/packages/aws-cdk-lib/aws-stepfunctions/lib/states/custom-state.ts#L74 This PR fixes this regression and clarifies the current behavior for configuring the Retry and Catch field. Previously, I added the `addRetry` method to add the Retry field and did not render the Retry field in the stateJson in #28598, but this is initially a regression and should have been fixed. Closes #28769 Relates #28586 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 4a7c432 commit 3c33e2c

File tree

8 files changed

+102
-7
lines changed

8 files changed

+102
-7
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.ALL\"],\"IntervalSeconds\":10,\"MaxAttempts\":5}],\"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\":\"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}",
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

+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.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ const stateJson = {
2323
},
2424
},
2525
ResultPath: null,
26+
Retry: [{
27+
ErrorEquals: [sfn.Errors.PERMISSIONS],
28+
IntervalSeconds: 20,
29+
MaxAttempts: 2,
30+
}],
2631
};
2732

2833
const failure = new sfn.Fail(stack, 'failed', {
@@ -36,7 +41,7 @@ const custom = new sfn.CustomState(stack, 'my custom task', {
3641

3742
custom.addCatch(failure);
3843
custom.addRetry({
39-
errors: [sfn.Errors.ALL],
44+
errors: [sfn.Errors.TIMEOUT],
4045
interval: cdk.Duration.seconds(10),
4146
maxAttempts: 5,
4247
});

packages/aws-cdk-lib/aws-stepfunctions/README.md

+4
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,10 @@ Custom states can be chained together with any of the other states to create you
562562
definition. You will also need to provide any permissions that are required to the `role` that
563563
the State Machine uses.
564564

565+
The Retry and Catch fields are available for error handling.
566+
You can configure the Retry field by defining it in the JSON object or by adding it using the `addRetry` method.
567+
However, the Catch field cannot be configured by defining it in the JSON object, so it must be added using the `addCatch` method.
568+
565569
The following example uses the `DynamoDB` service integration to insert data into a DynamoDB table.
566570

567571
```ts

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

+8-1
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,17 @@ export class CustomState extends State implements IChainable, INextable {
6868
* Returns the Amazon States Language object for this state
6969
*/
7070
public toStateJson(): object {
71-
return {
71+
const state = {
7272
...this.renderNextEnd(),
7373
...this.stateJson,
7474
...this.renderRetryCatch(),
7575
};
76+
77+
// merge the Retry filed defined in the stateJson into the state
78+
if (Array.isArray(this.stateJson.Retry)) {
79+
state.Retry = [...state.Retry, ...this.stateJson.Retry];
80+
}
81+
82+
return state;
7683
}
7784
}

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

+79
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,83 @@ describe('Custom State', () => {
163163
},
164164
);
165165
});
166+
167+
test('respect the Retry field in the stateJson', () => {
168+
// GIVEN
169+
const custom = new sfn.CustomState(stack, 'Custom', {
170+
stateJson: {
171+
Type: 'Task',
172+
Resource: 'arn:aws:states:::dynamodb:putItem',
173+
Parameters: {
174+
TableName: 'MyTable',
175+
Item: {
176+
id: {
177+
S: 'MyEntry',
178+
},
179+
},
180+
},
181+
ResultPath: null,
182+
Retry: [
183+
{
184+
ErrorEquals: [sfn.Errors.TIMEOUT],
185+
IntervalSeconds: 20,
186+
MaxAttempts: 2,
187+
},
188+
{
189+
ErrorEquals: [sfn.Errors.RESULT_PATH_MATCH_FAILURE],
190+
IntervalSeconds: 20,
191+
MaxAttempts: 2,
192+
},
193+
],
194+
},
195+
});
196+
const chain = sfn.Chain.start(custom);
197+
198+
// WHEN
199+
custom.addRetry({
200+
errors: [sfn.Errors.PERMISSIONS],
201+
interval: cdk.Duration.seconds(10),
202+
maxAttempts: 5,
203+
});
204+
205+
// THEN
206+
expect(render(stack, chain)).toStrictEqual(
207+
{
208+
StartAt: 'Custom',
209+
States: {
210+
Custom: {
211+
Type: 'Task',
212+
Resource: 'arn:aws:states:::dynamodb:putItem',
213+
Parameters: {
214+
TableName: 'MyTable',
215+
Item: {
216+
id: {
217+
S: 'MyEntry',
218+
},
219+
},
220+
},
221+
ResultPath: null,
222+
Retry: [
223+
{
224+
ErrorEquals: ['States.Permissions'],
225+
IntervalSeconds: 10,
226+
MaxAttempts: 5,
227+
},
228+
{
229+
ErrorEquals: ['States.Timeout'],
230+
IntervalSeconds: 20,
231+
MaxAttempts: 2,
232+
},
233+
{
234+
ErrorEquals: ['States.ResultPathMatchFailure'],
235+
IntervalSeconds: 20,
236+
MaxAttempts: 2,
237+
},
238+
],
239+
End: true,
240+
},
241+
},
242+
},
243+
);
244+
});
166245
});

0 commit comments

Comments
 (0)