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): evaluate expression as a task construct #8555

Merged
merged 4 commits into from
Jun 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 9 additions & 12 deletions packages/@aws-cdk/aws-stepfunctions-tasks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,25 +164,22 @@ Use the `EvaluateExpression` to perform simple operations referencing state path
Example: convert a wait time from milliseconds to seconds, concat this in a message and wait:

```ts
const convertToSeconds = new sfn.Task(this, 'Convert to seconds', {
task: new tasks.EvaluateExpression({ expression: '$.waitMilliseconds / 1000' }),
resultPath: '$.waitSeconds'
const convertToSeconds = new tasks.EvaluateExpression(this, 'Convert to seconds', {
expression: '$.waitMilliseconds / 1000',
resultPath: '$.waitSeconds',
});

const createMessage = new sfn.Task(this, 'Create message', {
const createMessage = new tasks.EvaluateExpression(this, 'Create message', {
// Note: this is a string inside a string.
task: new tasks.EvaluateExpression({
expression: '`Now waiting ${$.waitSeconds} seconds...`',
runtime: lambda.Runtime.NODEJS_10_X,
}),
resultPath: '$.message'
resultPath: '$.message',
});

const publishMessage = new sfn.Task(this, 'Publish message', {
task: new tasks.PublishToTopic(topic, {
message: sfn.TaskInput.fromDataAt('$.message'),
}),
resultPath: '$.sns'
const publishMessage = new tasks.SnsPublish(this, 'Publish message', {
topic,
message: sfn.TaskInput.fromDataAt('$.message'),
resultPath: '$.sns',
});

const wait = new sfn.Wait(this, 'Wait', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as path from 'path';
*
* @experimental
*/
export interface EvaluateExpressionProps {
export interface EvaluateExpressionProps extends sfn.TaskStateBaseProps {
/**
* The expression to evaluate. The expression may contain state paths.
*
Expand Down Expand Up @@ -49,11 +49,29 @@ export interface Event {
*
* @experimental
*/
export class EvaluateExpression implements sfn.IStepFunctionsTask {
constructor(private readonly props: EvaluateExpressionProps) {
export class EvaluateExpression extends sfn.TaskStateBase {
protected readonly taskMetrics?: sfn.TaskMetricsConfig;
protected readonly taskPolicies?: iam.PolicyStatement[];

private readonly evalFn: lambda.SingletonFunction;

constructor(scope: cdk.Construct, id: string, private readonly props: EvaluateExpressionProps) {
super(scope, id, props);

this.evalFn = createEvalFn(this.props.runtime || lambda.Runtime.NODEJS_10_X, this);

this.taskPolicies = [
new iam.PolicyStatement({
resources: [this.evalFn.functionArn],
actions: ['lambda:InvokeFunction'],
}),
];
}

public bind(task: sfn.Task): sfn.StepFunctionsTaskConfig {
/**
* @internal
*/
protected _renderTask(): any {
const matches = this.props.expression.match(/\$[.\[][.a-zA-Z[\]0-9]+/g);

let expressionAttributeValues = {};
Expand All @@ -67,19 +85,13 @@ export class EvaluateExpression implements sfn.IStepFunctionsTask {
);
}

const evalFn = createEvalFn(this.props.runtime || lambda.Runtime.NODEJS_10_X, task);

const parameters: Event = {
expression: this.props.expression,
expressionAttributeValues,
};
return {
resourceArn: evalFn.functionArn,
policyStatements: [new iam.PolicyStatement({
resources: [evalFn.functionArn],
actions: ['lambda:InvokeFunction'],
})],
parameters,
Resource: this.evalFn.functionArn,
Parameters: sfn.FieldUtils.renderObject(parameters),
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ beforeEach(() => {

test('Eval with Node.js', () => {
// WHEN
const task = new sfn.Task(stack, 'Task', {
task: new tasks.EvaluateExpression({
expression: '$.a + $.b',
}),
const task = new tasks.EvaluateExpression(stack, 'Task', {
expression: '$.a + $.b',
});
new sfn.StateMachine(stack, 'SM', {
definition: task,
Expand All @@ -25,14 +23,11 @@ test('Eval with Node.js', () => {
'Fn::Join': [
'',
[
'{"StartAt":"Task","States":{"Task":{"End":true,"Parameters":{"expression":"$.a + $.b","expressionAttributeValues":{"$.a.$":"$.a","$.b.$":"$.b"}},"Type":"Task","Resource":"',
'{"StartAt":"Task","States":{"Task":{"End":true,"Type":"Task","Resource":"',
{
'Fn::GetAtt': [
'Evala0d2ce44871b4e7487a1f5e63d7c3bdc4DAC06E1',
'Arn',
],
'Fn::GetAtt': ['Evala0d2ce44871b4e7487a1f5e63d7c3bdc4DAC06E1', 'Arn'],
},
'"}}}',
'","Parameters":{"expression":"$.a + $.b","expressionAttributeValues":{"$.a.$":"$.a","$.b.$":"$.b"}}}}}',
],
],
},
Expand All @@ -45,10 +40,8 @@ test('Eval with Node.js', () => {

test('expression does not contain paths', () => {
// WHEN
const task = new sfn.Task(stack, 'Task', {
task: new tasks.EvaluateExpression({
expression: '2 + 2',
}),
const task = new tasks.EvaluateExpression(stack, 'Task', {
expression: '2 + 2',
});
new sfn.StateMachine(stack, 'SM', {
definition: task,
Expand All @@ -59,14 +52,11 @@ test('expression does not contain paths', () => {
'Fn::Join': [
'',
[
'{"StartAt":"Task","States":{"Task":{"End":true,"Parameters":{"expression":"2 + 2",\"expressionAttributeValues\":{}},"Type":"Task","Resource":"',
'{"StartAt":"Task","States":{"Task":{"End":true,"Type":"Task","Resource":"',
{
'Fn::GetAtt': [
'Evala0d2ce44871b4e7487a1f5e63d7c3bdc4DAC06E1',
'Arn',
],
'Fn::GetAtt': ['Evala0d2ce44871b4e7487a1f5e63d7c3bdc4DAC06E1', 'Arn'],
},
'"}}}',
'","Parameters":{"expression":"2 + 2","expressionAttributeValues":{}}}}}',
],
],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,40 +142,40 @@
"StateMachine2E01A3A5": {
"Type": "AWS::StepFunctions::StateMachine",
"Properties": {
"RoleArn": {
"Fn::GetAtt": [
"StateMachineRoleB840431D",
"Arn"
]
},
"DefinitionString": {
"Fn::Join": [
"",
[
"{\"StartAt\":\"Sum\",\"States\":{\"Sum\":{\"Next\":\"Multiply\",\"Parameters\":{\"expression\":\"$.a + $.b\",\"expressionAttributeValues\":{\"$.a.$\":\"$.a\",\"$.b.$\":\"$.b\"}},\"Type\":\"Task\",\"Resource\":\"",
"{\"StartAt\":\"Sum\",\"States\":{\"Sum\":{\"Next\":\"Multiply\",\"Type\":\"Task\",\"ResultPath\":\"$.c\",\"Resource\":\"",
{
"Fn::GetAtt": [
"Evala0d2ce44871b4e7487a1f5e63d7c3bdc4DAC06E1",
"Arn"
]
},
"\",\"ResultPath\":\"$.c\"},\"Multiply\":{\"Next\":\"Wait\",\"Parameters\":{\"expression\":\"$.c * 2\",\"expressionAttributeValues\":{\"$.c.$\":\"$.c\"}},\"Type\":\"Task\",\"Resource\":\"",
"\",\"Parameters\":{\"expression\":\"$.a + $.b\",\"expressionAttributeValues\":{\"$.a.$\":\"$.a\",\"$.b.$\":\"$.b\"}}},\"Multiply\":{\"Next\":\"Wait\",\"Type\":\"Task\",\"ResultPath\":\"$.d\",\"Resource\":\"",
{
"Fn::GetAtt": [
"Evala0d2ce44871b4e7487a1f5e63d7c3bdc4DAC06E1",
"Arn"
]
},
"\",\"ResultPath\":\"$.d\"},\"Wait\":{\"Type\":\"Wait\",\"SecondsPath\":\"$.d\",\"Next\":\"Now\"},\"Now\":{\"End\":true,\"Parameters\":{\"expression\":\"(new Date()).toUTCString()\",\"expressionAttributeValues\":{}},\"Type\":\"Task\",\"Resource\":\"",
"\",\"Parameters\":{\"expression\":\"$.c * 2\",\"expressionAttributeValues\":{\"$.c.$\":\"$.c\"}}},\"Wait\":{\"Type\":\"Wait\",\"SecondsPath\":\"$.d\",\"Next\":\"Now\"},\"Now\":{\"End\":true,\"Type\":\"Task\",\"ResultPath\":\"$.now\",\"Resource\":\"",
{
"Fn::GetAtt": [
"Evala0d2ce44871b4e7487a1f5e63d7c3bdc4DAC06E1",
"Arn"
]
},
"\",\"ResultPath\":\"$.now\"}}}"
"\",\"Parameters\":{\"expression\":\"(new Date()).toUTCString()\",\"expressionAttributeValues\":{}}}}}"
]
]
},
"RoleArn": {
"Fn::GetAtt": [
"StateMachineRoleB840431D",
"Arn"
]
}
},
"DependsOn": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,29 @@ import * as tasks from '../lib';
const app = new cdk.App();
const stack = new cdk.Stack(app, 'aws-stepfunctions-integ');

const sum = new sfn.Task(stack, 'Sum', {
task: new tasks.EvaluateExpression({
expression: '$.a + $.b',
}),
const sum = new tasks.EvaluateExpression(stack, 'Sum', {
expression: '$.a + $.b',
resultPath: '$.c',
});

const multiply = new sfn.Task(stack, 'Multiply', {
task: new tasks.EvaluateExpression({
expression: '$.c * 2',
}),
const multiply = new tasks.EvaluateExpression(stack, 'Multiply', {
expression: '$.c * 2',
resultPath: '$.d',
});

const now = new sfn.Task(stack, 'Now', {
task: new tasks.EvaluateExpression({
expression: '(new Date()).toUTCString()',
}),
const now = new tasks.EvaluateExpression(stack, 'Now', {
expression: '(new Date()).toUTCString()',
resultPath: '$.now',
});

const statemachine = new sfn.StateMachine(stack, 'StateMachine', {
definition: sum
.next(multiply)
.next(new sfn.Wait(stack, 'Wait', {
time: sfn.WaitTime.secondsPath('$.d'),
}))
.next(
new sfn.Wait(stack, 'Wait', {
time: sfn.WaitTime.secondsPath('$.d'),
}),
)
.next(now),
});

Expand Down