Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(stepfunctions-tasks): support Associate Workflow Executions on StepFunctionsStartExecution via associateWithParent property #16475

Merged
merged 9 commits into from
Sep 15, 2021
15 changes: 15 additions & 0 deletions packages/@aws-cdk/aws-stepfunctions-tasks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,21 @@ new sfn.StateMachine(this, 'ParentStateMachine', {
});
```

You can utilize [Associate Workflow Executions](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-nested-workflows.html#nested-execution-startid)
via the `associateWithParent` property. This allows the Step Functions UI to link child
executions from parent executions, making it easier to trace execution flow across state machines.

```ts
const task = new tasks.StepFunctionsStartExecution(this, 'ChildTask', {
stateMachine: child,
associateWithParent: true,
});
```

This will add the payload `AWS_STEP_FUNCTIONS_STARTED_BY_EXECUTION_ID.$: $$.Execution.Id` to the
`input`property for you, which will pass the execution ID from the context object to the
execution input. It requires `input` to be an object or not be set at all.

### Invoke Activity

You can invoke a [Step Functions Activity](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-activities.html) which enables you to have
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ export interface StepFunctionsStartExecutionProps extends sfn.TaskStateBaseProps
* @default - None
*/
readonly name?: string;

/**
* Pass the execution ID from the context object to the execution input.
kaizencc marked this conversation as resolved.
Show resolved Hide resolved
* This allows the Step Functions UI to link child executions from parent executions, making it easier to trace execution flow across state machines.
*
* If you set this property to `true`, the `input` property must be an object (provided by `sfn.TaskInput.fromObject`) or omitted entirely.
*
* @see https://docs.aws.amazon.com/step-functions/latest/dg/concepts-nested-workflows.html#nested-execution-startid
kaizencc marked this conversation as resolved.
Show resolved Hide resolved
*
* @default - false
BenChaimberg marked this conversation as resolved.
Show resolved Hide resolved
*/
readonly associateWithParent?: boolean;
}

/**
Expand Down Expand Up @@ -59,6 +71,10 @@ export class StepFunctionsStartExecution extends sfn.TaskStateBase {
throw new Error('Task Token is required in `input` for callback. Use JsonPath.taskToken to set the token.');
}

if (this.props.associateWithParent && props.input && props.input.type !== sfn.InputType.OBJECT) {
throw new Error('Could not enable `associateWithParent` because `input` is taken directly from a JSON path. Use `sfn.TaskInput.fromObject` instead.');
}

this.taskPolicies = this.createScopedAccessPolicy();
}

Expand All @@ -70,10 +86,20 @@ export class StepFunctionsStartExecution extends sfn.TaskStateBase {
// suffix is only applicable when waiting for a nested state machine to complete (RUN_JOB)
// https://docs.aws.amazon.com/step-functions/latest/dg/connect-stepfunctions.html
const suffix = this.integrationPattern === sfn.IntegrationPattern.RUN_JOB ? ':2' : '';
let input: any;
if (this.props.associateWithParent) {
const associateWithParentEntry = {
AWS_STEP_FUNCTIONS_STARTED_BY_EXECUTION_ID: sfn.JsonPath.stringAt('$$.Execution.Id'),
};
input = this.props.input ? { ...this.props.input.value, ...associateWithParentEntry } : associateWithParentEntry;
} else {
input = this.props.input ? this.props.input.value: sfn.TaskInput.fromJsonPathAt('$').value;
}

return {
Resource: `${integrationResourceArn('states', 'startExecution', this.integrationPattern)}${suffix}`,
Parameters: sfn.FieldUtils.renderObject({
Input: this.props.input ? this.props.input.value : sfn.TaskInput.fromJsonPathAt('$').value,
Input: input,
StateMachineArn: this.props.stateMachine.stateMachineArn,
Name: this.props.name,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,55 @@ test('Execute State Machine - Wait For Task Token - Missing Task Token', () => {
});
}).toThrow('Task Token is required in `input` for callback. Use JsonPath.taskToken to set the token.');
});

test('Execute State Machine - Associate With Parent - Input Provided', () => {
const task = new StepFunctionsStartExecution(stack, 'ChildTask', {
stateMachine: child,
input: sfn.TaskInput.fromObject({
token: sfn.JsonPath.taskToken,
}),
kaizencc marked this conversation as resolved.
Show resolved Hide resolved
associateWithParent: true,
});

new sfn.StateMachine(stack, 'ParentStateMachine', {
definition: task,
});

expect(stack.resolve(task.toStateJson())).toMatchObject({
Parameters: {
Input: {
'token.$': '$$.Task.Token',
'AWS_STEP_FUNCTIONS_STARTED_BY_EXECUTION_ID.$': '$$.Execution.Id',
},
},
});
});

test('Execute State Machine - Associate With Parent - Input Not Provided', () => {
const task = new StepFunctionsStartExecution(stack, 'ChildTask', {
stateMachine: child,
associateWithParent: true,
});

new sfn.StateMachine(stack, 'ParentStateMachine', {
definition: task,
});

expect(stack.resolve(task.toStateJson())).toMatchObject({
Parameters: {
Input: {
'AWS_STEP_FUNCTIONS_STARTED_BY_EXECUTION_ID.$': '$$.Execution.Id',
},
},
});
});

test('Execute State Machine - Associate With Parent - Incorrect Input Type', () => {
expect(() => {
new StepFunctionsStartExecution(stack, 'ChildTask', {
stateMachine: child,
associateWithParent: true,
input: sfn.TaskInput.fromText('{ "token.$": "$$.Task.Token" }'),
});
}).toThrow('Could not enable `associateWithParent` because `input` is taken directly from a JSON path. Use `sfn.TaskInput.fromObject` instead.');
});