Skip to content

Commit

Permalink
fix(stepfunctions): the retry field in CustomState is not iterable (#…
Browse files Browse the repository at this point in the history
…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*
  • Loading branch information
abdelnn committed Mar 12, 2024
1 parent 0c73143 commit a1fbd51
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 8 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Expand Up @@ -20,7 +20,7 @@
"StateMachine2E01A3A5": {
"Type": "AWS::StepFunctions::StateMachine",
"Properties": {
"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}",
"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}",
"RoleArn": {
"Fn::GetAtt": [
"StateMachineRoleB840431D",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Expand Up @@ -39,14 +39,18 @@ const custom = new sfn.CustomState(stack, 'my custom task', {
stateJson,
});

const customWithInlineRetry = new sfn.CustomState(stack, 'my custom task with inline Retriers', {
stateJson,
});

custom.addCatch(failure);
custom.addRetry({
errors: [sfn.Errors.TIMEOUT],
interval: cdk.Duration.seconds(10),
maxAttempts: 5,
});

const chain = sfn.Chain.start(custom).next(finalStatus);
const chain = sfn.Chain.start(custom).next(customWithInlineRetry).next(finalStatus);

const sm = new sfn.StateMachine(stack, 'StateMachine', {
definition: chain,
Expand Down
Expand Up @@ -74,9 +74,9 @@ export class CustomState extends State implements IChainable, INextable {
...this.renderRetryCatch(),
};

// merge the Retry filed defined in the stateJson into the state
// merge the Retry field defined in the stateJson into the state
if (Array.isArray(this.stateJson.Retry)) {
state.Retry = [...state.Retry, ...this.stateJson.Retry];
state.Retry = Array.isArray(state.Retry) ? [...state.Retry, ...this.stateJson.Retry] : [...this.stateJson.Retry];
}

return state;
Expand Down
67 changes: 67 additions & 0 deletions packages/aws-cdk-lib/aws-stepfunctions/test/custom-state.test.ts
Expand Up @@ -242,4 +242,71 @@ describe('Custom State', () => {
},
);
});

test('expect retry to not fail when specifying strategy inline', () => {
// GIVEN
const custom = new sfn.CustomState(stack, 'Custom', {
stateJson: {
Type: 'Task',
Resource: 'arn:aws:states:::dynamodb:putItem',
Parameters: {
TableName: 'MyTable',
Item: {
id: {
S: 'MyEntry',
},
},
},
ResultPath: null,
Retry: [
{
ErrorEquals: [
'Lambda.ServiceException',
'Lambda.AWSLambdaException',
'Lambda.SdkClientException',
'Lambda.TooManyRequestsException',
],
IntervalSeconds: 20,
MaxAttempts: 2,
},
],
},
});
const chain = sfn.Chain.start(custom);

// THEN
expect(render(stack, chain)).toStrictEqual(
{
StartAt: 'Custom',
States: {
Custom: {
Type: 'Task',
Resource: 'arn:aws:states:::dynamodb:putItem',
Parameters: {
TableName: 'MyTable',
Item: {
id: {
S: 'MyEntry',
},
},
},
ResultPath: null,
Retry: [
{
ErrorEquals: [
'Lambda.ServiceException',
'Lambda.AWSLambdaException',
'Lambda.SdkClientException',
'Lambda.TooManyRequestsException',
],
IntervalSeconds: 20,
MaxAttempts: 2,
},
],
End: true,
},
},
},
);
});
});

0 comments on commit a1fbd51

Please sign in to comment.