1st Career
2nd Career
Task
Choice
Task
Task (end=true)
Wait
Fail
Microservices
Aurora
DynamoDB
S3
Elasticache
SNS
SQS
API Gateway
SES
EventBridge
Lambda
ECS
Batch
Fargate
Aurora
DynamoDB
S3
Elasticache
SNS
SQS
SES
EventBridge
Lambda
ECS
Batch
Fargate
We need to externalize the workflow orchestration.
We want to spend our time solving business problems, but we write code to
Microservices
Aurora
DynamoDB
S3
Elasticache
SNS
SQS
API Gateway
SES
EventBridge
Lambda
ECS
Batch
Fargate
{ "Comment": "My Batch Job workflow", "StartAt": "Submit Job", "States": { "Submit Job": {
"HelloWorld": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:HelloWorld",
"Next": "NextState",
"Comment": "Executes the HelloWorld Lambda function"
}
The operators “@”, “,”, “:”, and “?” are not supported
2016-03-14T01:59:00Z
{
"foo": 123,
"bar": ["a", "b", "c"],
"car": {
"cdr": true
}
}
$.foo => 123 $.bar => ["a", "b", "c"] $.car.cdr => true
$.store.book $.store\.book $.\stor\e.boo\k $.store.book.title $.foo.\.bar $.foo\@bar.baz\[\[.\?pretty $.&Ж中.\uD800\uDF46 $.ledgers.branch[0].pending.count $.ledgers.branch[0] $.ledgers[0][22][315].foo $['store']['book'] $['store'][0]['book']
{
"StartAt": "Add",
"States": {
"Add": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:Add",
"InputPath": "$.numbers",
"ResultPath": "$.sum"
"End": true
}
}
}
{
"title": "Numbers to add",
"numbers": { "val1": 3, "val2": 4 }
}
Input:
{
"title": "Numbers to add",
"numbers": { "val1": 3, "val2": 4 },
"sum": 7
}
Output:
"Preapre Data": {
"Type": "Task",
"Resource": "arn:aws:swf:us-east-1:123456789012:task:X",
"Next": "Y",
"Parameters": {
"flagged": true,
"parts": {
"first.$": "$.vals[0]",
"last3.$": "$.vals[3:]"
}
}
}
{
"flagged": 7,
"vals": [0, 10, 20, 30, 40, 50]
}
Input:
{
"flagged": true,
"parts": {
"first": 0,
"last3": [30, 40, 50]
}
}
Output:
"Retry" : [ {
"ErrorEquals": [ "States.Timeout" ],
"IntervalSeconds": 3,
"MaxAttempts": 3,
"BackoffRate": 2.0
} ]
Interpretation:
- If a timeout error occurs, wait 3 seconds, then retry
- If a timeout occurs again, wait 3.0s x 2.0 (6.0 seconds), then retry
- If a timeout occurs again, wait 6.0s x 2.0 (12.0 seconds), then retry
"Catch": [
{
"ErrorEquals": [ "java.lang.Exception" ],
"ResultPath": "$.error-info",
"Next": "RecoveryState"
},
{
"ErrorEquals": [ "States.ALL" ],
"Next": "EndMachine"
}
]
"No-op": {
"Type": "Pass",
"Result": {
"x-datum": 0.381018,
"y-datum": 622.226993
},
"ResultPath": "$.coords",
"Next": "End"
}
{ "geo-ref": "Home" }
Input
{
"geo-ref": "Home",
"coords": {
"x-datum": 0.381018,
"y-datum": 622.226993
}
}
Output
If either timeout exceeded, a "States.Timeout" error occurs
"TaskState": {
"Comment": "Task State example",
"Type": "Task",
"Resource": "arn:aws:swf:us-east-1:123456789012:task:HelloWorld",
"Next": "NextState",
"TimeoutSeconds": 300,
"HeartbeatSeconds": 60
}
"ChoiceStateX": {
"Type" : "Choice",
"Choices": [
{
"Not": {
"Variable": "$.type",
"StringEquals": "Private"
},
"Next": "Public"
},
{
"And": [
{
"Variable": "$.value",
"NumericGreaterThanEquals": 20
},
{
"Variable": "$.value",
"NumericLessThan": 30
}
],
"Next": "ValueInTwenties"
}
],
"Default": "DefaultState"
},
...
...
"Public": {
"Type" : "Task",
"Resource":
"arn:aws:lambda:...:function:Foo",
"Next": "NextState"
},
"ValueInTwenties": {
"Type" : "Task",
"Resource":
"arn:aws:lambda:...:function:Bar",
"Next": "NextState"
},
"DefaultState": {
"Type": "Fail",
"Cause": "No Matches!"
}
"wait_ten_seconds" : {
"Type" : "Wait",
"Seconds" : 10,
"Next": "NextState"
}
"wait_until" : {
"Type": "Wait",
"Timestamp": "2016-03-14T01:59:00Z",
"Next": "NextState"
}
"wait_some_seconds" : { "Type" : "Wait", "SecondsPath" : "$.secondsDelay", "Next": "NextState" }
"wait_until" : {
"Type": "Wait",
"TimestampPath": "$.expirydate",
"Next": "NextState"
}
"LookupCustomerInfo": {
"Type": "Parallel",
"Branches": [
{
"StartAt": "LookupAddress",
"States": {
"LookupAddress": {
"Type": "Task",
"Resource":
"arn:aws:lambda:us-east-1:123456789012:function:AddressFinder",
"End": true
}
}
},
{
"StartAt": "LookupPhone",
"States": {
"LookupPhone": {
"Type": "Task",
"Resource":
"arn:aws:lambda:us-east-1:123456789012:function:PhoneFinder",
"End": true
}
}
}
],
"Next": "NextState"
}
"FunWithMath": {
"Type": "Parallel",
"Branches": [
{
"StartAt": "Add",
"States": {
"Add": {
"Type": "Task",
"Resource": "arn:aws:swf:::task:Add",
"End": true
}
}
},
{
"StartAt": "Subtract",
"States": {
"Subtract": {
"Type": "Task",
"Resource": "arn:aws:swf:::task:Subtract",
"End": true
}
}
}
],
"Next": "NextState"
}
[3, 2]
Input:
[5, 1]
Output:
"Completed": { "Type": "Succeed" }
"FailState": { "Type": "Fail", "Error": "States.Timeout", "Cause": "Report generation timed out" }
{
"Comment": "An example of the Amazon States Language.",
"StartAt": "Submit Job",
"States": {
"Submit Job": {
"Type": "Task",
"Resource":
"arn:<PARTITION>:lambda:::function:SubmitJob",
"ResultPath": "$.guid",
"Next": "Wait X Seconds",
"Retry": [
{
"ErrorEquals": ["States.ALL"],
"IntervalSeconds": 1,
"MaxAttempts": 3,
"BackoffRate": 2
}
]
},
"Wait X Seconds": {
"Type": "Wait",
"SecondsPath": "$.wait_time",
"Next": "Get Job Status"
},
...
...
"Get Job Status": {
"Type": "Task",
"Resource":
"arn:<PARTITION>:lambda:::function:CheckJob",
"Next": "Job Complete?",
"InputPath": "$.guid",
"ResultPath": "$.status",
"Retry": [
{
"ErrorEquals": ["States.ALL"],
"IntervalSeconds": 1,
"MaxAttempts": 3,
"BackoffRate": 2
}
]
},
"Job Complete?": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.status",
"StringEquals": "FAILED",
"Next": "Job Failed"
},
{
"Variable": "$.status",
"StringEquals": "SUCCEEDED",
"Next": "Get Final Job Status"
}
],
"Default": "Wait X Seconds"
},
...
...
"Job Failed": {
"Type": "Fail",
"Cause": "AWS Batch Job Failed",
"Error": "DescribeJob returned FAILED"
},
"Get Final Job Status": {
"Type": "Task",
"Resource":
"arn:<PARTITION>:lambda:::function:CheckJob",
"InputPath": "$.guid",
"End": true,
"Retry": [
{
"ErrorEquals": ["States.ALL"],
"IntervalSeconds": 1,
"MaxAttempts": 3,
"BackoffRate": 2
}
]
}
}
}
Task
Choice
Task
Task (end=true)
Wait
Fail
{
"Comment": "A simple AWS Batch workflow",
"StartAt": "Submit Job",
"States": {
"Submit Job": {
"Type": "Task",
"Resource":
"arn:<PARTITION>:lambda:::function:SubmitJob",
"ResultPath": "$.guid",
"Next": "Wait X Seconds",
"Retry": [
{
"ErrorEquals": ["States.ALL"],
"IntervalSeconds": 1,
"MaxAttempts": 3,
"BackoffRate": 2
}
]
},
...
}
...
"Wait X Seconds": {
"Type": "Wait",
"SecondsPath": "$.wait_time",
"Next": "Get Job Status"
},
...
...
"Get Job Status": {
"Type": "Task",
"Resource":
"arn:<PARTITION>:lambda:::function:CheckJob",
"Next": "Job Complete?",
"InputPath": "$.guid",
"ResultPath": "$.status",
"Retry": [
{
"ErrorEquals": ["States.ALL"],
"IntervalSeconds": 1,
"MaxAttempts": 3,
"BackoffRate": 2
}
]
},
...
...
"Job Complete?": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.status",
"StringEquals": "FAILED",
"Next": "Job Failed"
},
{
"Variable": "$.status",
"StringEquals": "SUCCEEDED",
"Next": "Get Final Job Status"
}
],
"Default": "Wait X Seconds"
},
...
...
"Get Final Job Status": {
"Type": "Task",
"Resource":
"arn:<PARTITION>:lambda:::function:CheckJob",
"InputPath": "$.guid",
"End": true,
"Retry": [
{
"ErrorEquals": ["States.ALL"],
"IntervalSeconds": 1,
"MaxAttempts": 3,
"BackoffRate": 2
}
]
}
...
...
"Job Failed": {
"Type": "Fail",
"Cause": "AWS Batch Job Failed",
"Error": "DescribeJob returned FAILED"
},
...
Step Functions works directly with some AWS Services
No Lambda required!
Examples
Launch a Batch Job and consume its results
Insert or get a record from DynamoDB
Publish to SNS topic or to a SQS queue
Even launch another Step Functions State Machine
Request / Response
Run a job
Wait for a callback with the Task Token
"Send message to SNS":{
"Type":"Task",
"Resource":"arn:aws:states:::sns:publish",
"Parameters":{
"TopicArn":"arn:aws:sns:us-east-1:123456789012:myTopic",
"Message":"Hello from Step Functions!"
},
"Next":"NEXT_STATE"
}
"Manage Batch task": {
"Type": "Task",
"Resource": "arn:aws:states:::batch:submitJob.sync",
"Parameters": {
"JobDefinition": "arn:aws:batch:us-east-2:123456789012:job-definition/testJobDefinition",
"JobName": "testJob",
"JobQueue": "arn:aws:batch:us-east-2:123456789012:job-queue/testQueue"
}, "Next": "NEXT_STATE"
}
Post Message w/ TT
Pull Message
Step F()
SQS
Callback w/ TT
"Send message to SQS": {
"Type": "Task",
"Resource": "arn:aws:states:::sqs:sendMessage.waitForTaskToken",
"Parameters": {
"QueueUrl": "https://sqs.us-east-2.../myQueue",
"MessageBody": {
"Message": "Hello from Step Functions!",
"TaskToken.$": "$$.Task.Token"
}
}, "Next": "NEXT_STATE" }
stls_HelloWorldExample
WaitForCallbackStateMachine
DynamoDBToSQS
NestingPatternMainStateMachine
docker run -p 8083:8083 /
--env-file aws-stepfunctions-local-credentials.txt /
amazon/aws-stepfunctions-local
import sfn = require('@aws-cdk/aws-stepfunctions');
import tasks = require('@aws-cdk/aws-stepfunctions-tasks');
const submitLambda = new lambda.Function(this, 'SubmitLambda', { ... });
const getStatusLambda = new lambda.Function(this, 'CheckLambda', { ... });
const submitJob = new sfn.Task(this, 'Submit Job', {
task: new tasks.InvokeFunction(submitLambda),
// Put Lambda's result here in the execution's state object
resultPath: '$.guid',
});
const waitX = new sfn.Wait(this, 'Wait X Seconds', {
duration: sfn.WaitDuration.secondsPath('$.wait_time'),
});
const getStatus = new sfn.Task(this, 'Get Job Status', {
task: new tasks.InvokeFunction(getStatusLambda),
// Pass just the field named "guid" into the Lambda, put the
// Lambda's result in a field called "status"
inputPath: '$.guid',
resultPath: '$.status',
});
const jobFailed = new sfn.Fail(this, 'Job Failed', {
cause: 'AWS Batch Job Failed',
error: 'DescribeJob returned FAILED',
});
const finalStatus = new sfn.Task(this, 'Get Final Job Status', {
task: new tasks.InvokeFunction(getStatusLambda),
// Use "guid" field as input, output of the Lambda becomes the
// entire state machine output.
inputPath: '$.guid',
});
const definition = submitJob
.next(waitX)
.next(getStatus)
.next(new sfn.Choice(this, 'Job Complete?')
// Look at the "status" field
.when(sfn.Condition.stringEquals('$.status', 'FAILED'), jobFailed)
.when(sfn.Condition.stringEquals('$.status', 'SUCCEEDED'), finalStatus)
.otherwise(waitX));
new sfn.StateMachine(this, 'StateMachine', {
definition,
timeout: Duration.minutes(5)
});