Skip to content

Commit

Permalink
Add warning on multiple retry and catch sources
Browse files Browse the repository at this point in the history
  • Loading branch information
jormello committed Apr 6, 2024
1 parent c9c3b20 commit c8edf8a
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 0 deletions.
49 changes: 49 additions & 0 deletions packages/aws-cdk-lib/aws-stepfunctions/lib/states/custom-state.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Construct } from 'constructs';
import { State } from './state';
import { Chain } from '..';
import { Annotations } from '../../../core/';
import { CatchProps, IChainable, INextable, RetryProps } from '../types';

/**
Expand Down Expand Up @@ -74,6 +75,14 @@ export class CustomState extends State implements IChainable, INextable {
...this.renderRetryCatch(),
};

if (this.hasMultipleRetrySources(state)) {
this.addMultipleRetrySourcesWarning();
}

if (this.hasMultipleCatchSources(state)) {
this.addMultipleCatchSourcesWarning();
}

// Retriers and Catchers can be specified directly in the stateJson or indirectly to the construct with addRetry() and addCatch().
// renderRetryCatch() only renders the indirectly supplied Retriers and Catchers, so we need to manually merge in those directly in the stateJson
if (Array.isArray(this.stateJson.Retry)) {
Expand All @@ -86,4 +95,44 @@ export class CustomState extends State implements IChainable, INextable {

return state;
}

private hasMultipleRetrySources(state: any): boolean {
if (!Array.isArray(state.Retry)) {
return false;
}

if (!Array.isArray(this.stateJson.Retry)) {
return false;
}

return state.Retry.length > 0 && this.stateJson.Retry.length > 0;
}

private hasMultipleCatchSources(state: any): boolean {
if (!Array.isArray(state.Catch)) {
return false;
}

if (!Array.isArray(this.stateJson.Catch)) {
return false;
}

return state.Catch.length > 0 && this.stateJson.Catch.length > 0;
}

private addMultipleRetrySourcesWarning(): void {
Annotations.of(this).addWarningV2('@aws-cdk/aws-stepfunctions:multipleRetrySources', [
'CustomState constructs can configure state retries using the stateJson property or by using the addRetry() function.',
'When retries are configured using both of these, the state definition\'s Retry field is generated ',
'by first rendering retries from addRetry(), then rendering retries from the stateJson.',
].join('\n'));
}

private addMultipleCatchSourcesWarning(): void {
Annotations.of(this).addWarningV2('@aws-cdk/aws-stepfunctions:multipleCatchSources', [
'CustomState constructs can configure state catchers using the stateJson property or by using the addCatch() function.',
'When catchers are configured using both of these, the state definition\'s Catch field is generated ',
'by first rendering catchers from addCatch(), then rendering catchers from the stateJson.',
].join('\n'));
}
}
71 changes: 71 additions & 0 deletions packages/aws-cdk-lib/aws-stepfunctions/test/custom-state.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { render } from './private/render-util';
import { Annotations, Match } from '../../assertions';
import * as cdk from '../../core';
import * as sfn from '../lib';
import { Errors } from '../lib/types';
Expand Down Expand Up @@ -451,4 +452,74 @@ describe('Custom State', () => {
},
);
});

test('expect warning message to be emitted when retries specified both in stateJson and through addRetry()', () => {
const customState = new sfn.CustomState(stack, 'my custom task', {
stateJson: {
Type: 'Task',
Resource: 'arn:aws:states:::dynamodb:putItem',
Parameters: {
TableName: 'my-cool-table',
Item: {
id: {
S: 'my-entry',
},
},
},
Retry: [{
ErrorEquals: ['States.TaskFailed'],
}],
},
});

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

new sfn.StateMachine(stack, 'StateMachine', {
definition: sfn.Chain.start(customState),
timeout: cdk.Duration.seconds(30),
});

Annotations.fromStack(stack).hasWarning('/Default/my custom task', Match.stringLikeRegexp('CustomState constructs can configure state retries'));
});

test('expect warning message to be emitted when catchers specified both in stateJson and through addCatch()', () => {
const customState = new sfn.CustomState(stack, 'my custom task', {
stateJson: {
Type: 'Task',
Resource: 'arn:aws:states:::dynamodb:putItem',
Parameters: {
TableName: 'my-cool-table',
Item: {
id: {
S: 'my-entry',
},
},
},
Catch: [
{
ErrorEquals: ['States.Timeout'],
Next: 'Failed',
},
],
},
});

const failure = new sfn.Fail(stack, 'Failed', {
error: 'DidNotWork',
cause: 'We got stuck',
});

customState.addCatch(failure, { errors: [Errors.TIMEOUT] });

new sfn.StateMachine(stack, 'StateMachine', {
definition: sfn.Chain.start(customState),
timeout: cdk.Duration.seconds(30),
});

Annotations.fromStack(stack).hasWarning('/Default/my custom task', Match.stringLikeRegexp('CustomState constructs can configure state catchers'));
});
});

0 comments on commit c8edf8a

Please sign in to comment.