Skip to content

Commit 9ce288f

Browse files
authored
Merge branch 'main' into updateDocs
2 parents e74fc34 + 5ec3ec9 commit 9ce288f

4 files changed

Lines changed: 147 additions & 9 deletions

File tree

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,16 @@ const fail = new sfn.Fail(this, 'Fail', {
487487
});
488488
```
489489

490+
You can also use an intrinsic function that returns a string to specify CausePath and ErrorPath.
491+
The available functions include States.Format, States.JsonToString, States.ArrayGetItem, States.Base64Encode, States.Base64Decode, States.Hash, and States.UUID.
492+
493+
```ts
494+
const fail = new sfn.Fail(this, 'Fail', {
495+
errorPath: sfn.JsonPath.format('error: {}.', sfn.JsonPath.stringAt('$.someError')),
496+
causePath: "States.Format('cause: {}.', $.someCause)",
497+
});
498+
```
499+
490500
### Map
491501

492502
A `Map` state can be used to run a set of steps for each element of an input array.

packages/aws-cdk-lib/aws-stepfunctions/lib/states/fail.ts

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Construct } from 'constructs';
22
import { StateType } from './private/state-type';
33
import { renderJsonPath, State } from './state';
4+
import { Token } from '../../../core';
45
import { INextable } from '../types';
56

67
/**
@@ -31,6 +32,9 @@ export interface FailProps {
3132
/**
3233
* JsonPath expression to select part of the state to be the error to this state.
3334
*
35+
* You can also use an intrinsic function that returns a string to specify this property.
36+
* The allowed functions include States.Format, States.JsonToString, States.ArrayGetItem, States.Base64Encode, States.Base64Decode, States.Hash, and States.UUID.
37+
*
3438
* @default - No error path
3539
*/
3640
readonly errorPath?: string;
@@ -45,6 +49,9 @@ export interface FailProps {
4549
/**
4650
* JsonPath expression to select part of the state to be the cause to this state.
4751
*
52+
* You can also use an intrinsic function that returns a string to specify this property.
53+
* The allowed functions include States.Format, States.JsonToString, States.ArrayGetItem, States.Base64Encode, States.Base64Decode, States.Hash, and States.UUID.
54+
*
4855
* @default - No cause path
4956
*/
5057
readonly causePath?: string;
@@ -56,6 +63,16 @@ export interface FailProps {
5663
* Reaching a Fail state terminates the state execution in failure.
5764
*/
5865
export class Fail extends State {
66+
private static allowedIntrinsics = [
67+
'States.Format',
68+
'States.JsonToString',
69+
'States.ArrayGetItem',
70+
'States.Base64Encode',
71+
'States.Base64Decode',
72+
'States.Hash',
73+
'States.UUID',
74+
];
75+
5976
public readonly endStates: INextable[] = [];
6077

6178
private readonly error?: string;
@@ -80,9 +97,42 @@ export class Fail extends State {
8097
Type: StateType.FAIL,
8198
Comment: this.comment,
8299
Error: this.error,
83-
ErrorPath: renderJsonPath(this.errorPath),
100+
ErrorPath: this.isIntrinsicString(this.errorPath) ? this.errorPath : renderJsonPath(this.errorPath),
84101
Cause: this.cause,
85-
CausePath: renderJsonPath(this.causePath),
102+
CausePath: this.isIntrinsicString(this.causePath) ? this.causePath : renderJsonPath(this.causePath),
86103
};
87104
}
88-
}
105+
106+
/**
107+
* Validate this state
108+
*/
109+
protected validateState(): string[] {
110+
const errors = super.validateState();
111+
112+
if (this.errorPath && this.isIntrinsicString(this.errorPath) && !this.isAllowedIntrinsic(this.errorPath)) {
113+
errors.push(`You must specify a valid intrinsic function in errorPath. Must be one of ${Fail.allowedIntrinsics.join(', ')}`);
114+
}
115+
116+
if (this.causePath && this.isIntrinsicString(this.causePath) && !this.isAllowedIntrinsic(this.causePath)) {
117+
errors.push(`You must specify a valid intrinsic function in causePath. Must be one of ${Fail.allowedIntrinsics.join(', ')}`);
118+
}
119+
120+
if (this.error && this.errorPath) {
121+
errors.push('Fail state cannot have both error and errorPath');
122+
}
123+
124+
if (this.cause && this.causePath) {
125+
errors.push('Fail state cannot have both cause and causePath');
126+
}
127+
128+
return errors;
129+
}
130+
131+
private isIntrinsicString(jsonPath?: string): boolean {
132+
return !Token.isUnresolved(jsonPath) && !jsonPath?.startsWith('$');
133+
}
134+
135+
private isAllowedIntrinsic(intrinsic: string): boolean {
136+
return Fail.allowedIntrinsics.some(allowed => intrinsic.startsWith(allowed));
137+
}
138+
}

packages/aws-cdk-lib/aws-stepfunctions/test/state-machine-resources.test.ts

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,88 @@ describe('State Machine Resources', () => {
9696
});
9797
}),
9898

99+
test.each([
100+
[
101+
"States.Format('error: {}.', $.error)",
102+
"States.Format('cause: {}.', $.cause)",
103+
],
104+
[
105+
stepfunctions.JsonPath.format('error: {}.', stepfunctions.JsonPath.stringAt('$.error')),
106+
stepfunctions.JsonPath.format('cause: {}.', stepfunctions.JsonPath.stringAt('$.cause')),
107+
],
108+
])('Fail should render ErrorPath / CausePath correctly when specifying ErrorPath / CausePath using intrinsics', (errorPath, causePath) => {
109+
// GIVEN
110+
const app = new cdk.App();
111+
const stack = new cdk.Stack(app);
112+
const fail = new stepfunctions.Fail(stack, 'Fail', {
113+
errorPath,
114+
causePath,
115+
});
116+
117+
// WHEN
118+
const failState = stack.resolve(fail.toStateJson());
119+
120+
// THEN
121+
expect(failState).toStrictEqual({
122+
CausePath: "States.Format('cause: {}.', $.cause)",
123+
ErrorPath: "States.Format('error: {}.', $.error)",
124+
Type: 'Fail',
125+
});
126+
expect(() => app.synth()).not.toThrow();
127+
}),
128+
129+
test('fails in synthesis if error and errorPath are defined in Fail state', () => {
130+
// GIVEN
131+
const app = new cdk.App();
132+
const stack = new cdk.Stack(app);
133+
134+
// WHEN
135+
new stepfunctions.Fail(stack, 'Fail', {
136+
error: 'error',
137+
errorPath: '$.error',
138+
});
139+
140+
expect(() => app.synth()).toThrow(/Fail state cannot have both error and errorPath/);
141+
}),
142+
143+
test('fails in synthesis if cause and causePath are defined in Fail state', () => {
144+
// GIVEN
145+
const app = new cdk.App();
146+
const stack = new cdk.Stack(app);
147+
148+
// WHEN
149+
new stepfunctions.Fail(stack, 'Fail', {
150+
cause: 'cause',
151+
causePath: '$.cause',
152+
});
153+
154+
expect(() => app.synth()).toThrow(/Fail state cannot have both cause and causePath/);
155+
}),
156+
157+
test.each([
158+
'States.Array($.Id)',
159+
'States.ArrayPartition($.inputArray, 4)',
160+
'States.ArrayContains($.inputArray, $.lookingFor)',
161+
'States.ArrayRange(1, 9, 2)',
162+
'States.ArrayLength($.inputArray)',
163+
'States.JsonMerge($.json1, $.json2, false)',
164+
'States.StringToJson($.escapedJsonString)',
165+
'plainString',
166+
])('fails in synthesis if specifying invalid intrinsic functions in the causePath and errorPath (%s)', (intrinsic) => {
167+
// GIVEN
168+
const app = new cdk.App();
169+
const stack = new cdk.Stack(app);
170+
171+
// WHEN
172+
new stepfunctions.Fail(stack, 'Fail', {
173+
causePath: intrinsic,
174+
errorPath: intrinsic,
175+
});
176+
177+
expect(() => app.synth()).toThrow(/You must specify a valid intrinsic function in causePath. Must be one of States.Format, States.JsonToString, States.ArrayGetItem, States.Base64Encode, States.Base64Decode, States.Hash, States.UUID/);
178+
expect(() => app.synth()).toThrow(/You must specify a valid intrinsic function in errorPath. Must be one of States.Format, States.JsonToString, States.ArrayGetItem, States.Base64Encode, States.Base64Decode, States.Hash, States.UUID/);
179+
}),
180+
99181
testDeprecated('Task should render InputPath / Parameters / OutputPath correctly', () => {
100182
// GIVEN
101183
const stack = new cdk.Stack();
@@ -721,7 +803,6 @@ describe('State Machine Resources', () => {
721803
],
722804
});
723805
});
724-
725806
});
726807

727808
interface FakeTaskProps extends stepfunctions.TaskStateBaseProps {

tools/@aws-cdk/cdk-build-tools/config/jest.config.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,8 @@ module.exports = {
2222
},
2323
],
2424
},
25-
26-
// Limit workers to a reasonable fixed number. If we scale in the number of available CPUs, we will explode
27-
// our memory limit on the CodeBuild instance that has 72 CPUs.
28-
maxWorkers: Math.min(8, cpus().length - 1),
29-
25+
// Jest is resource greedy so this shouldn't be more than 50%
26+
maxWorkers: '50%',
3027
testEnvironment: 'node',
3128
coverageThreshold: {
3229
global: {

0 commit comments

Comments
 (0)