Step Functions Workflow Studio with Serverless Framework
Sebastian Bille
Posted on August 11, 2021
The serverless-step-functions plugin is a nifty Serverless Framework extension that allows you to define step functions directly within the serverless.yml
. However, the definitions for step functions tend to get messy fast and it's hard to visualize how a workflow actually looks and flows just from looking at the YAML. The Step Functions Workflow Studio helps you with exactly this by allowing you to interactively sketch out your state machine. In this post, I'll give you a brief walkthrough of how we can use the Workflow Studio together with the Step Functions plugin.
Creating a State Machine
To get started, navigate to the Step Functions page in the AWS Console and press "Create state machine".
Next, choose "Design your workflow visually", then go to Next.
From here, you can drag and drop Actions and Flows, tinker with the properties, flow, and error handling until you're happy with the design.
Set any resources that you want to eventually define in your serverless app to refer to a made-up value in the meantime - setting the Lambda Function name to just a string name for example. Once you're done, click "Next".
At last, we have our generated JSON schema for the state machine! But wait. Our Serverless template is in YAML, not JSON - how do we translate this into something that we can actually use?
As it turns out, YAML is just a superset of JSON, meaning all JSON is valid YAML. The JSON that was generated is in the form of Amazon State Languages spec, and that same spec is used by our serverless-step-functions plugin. This means that we can translate our JSON snippet to YAML using an online tool, such as Code Beatify, or a CLI tool such as yq.
Now that we've got the state machine defined in YAML, all we need to do is actually use it in the serverless.yml
.
Putting it together
If you don't already have a serverless project set up, check out my guide to a simple esbuild setup or just run
serverless
in your terminal to choose from one of the boilerplates.
The serverless-step-functions plugin extends the serverless.yml
format with a root stepFunctions
property. We'll use that to define our step function by pasting in our YAML snippet as the definition of the state machine.
// serverless.yml
[...]
stepFunctions:
stateMachines:
myStateMachine:
name: MyStateMachine
[your generated state machine goes here]
Keep in mind that any references to Lambda functions or other services that we used placeholder references for needs to be updated to refer to the actual resources we want them to point to. As an example, a Lambda definition might look like this when generated:
FirstFunction:
Type: Task
Resource: arn:aws:states:::lambda:invoke
OutputPath: $.Payload
Parameters:
Payload.$: $
FunctionName: firstFunction
and we can change that to instead refer to a firstFunction
Lambda defined in our stack by changing it to:
FirstFunction:
Type: Task
Resource: !GetAtt firstFunction.Arn
OutputPath: "$.Payload"
Parameters:
Payload.$: "$"
For the workflow from the examples above, this is what the full serverless.yml
might look like.
service: step-functions-demo
plugins:
- serverless-step-functions
provider:
name: aws
runtime: nodejs14.x
stepFunctions:
stateMachines:
myStateMachine:
name: MyStateMachine
definition:
Comment: This is your state machine
StartAt: First function
States:
First function:
Type: Task
Resource: !GetAtt firstFunction.Arn
OutputPath: "$.Payload"
Parameters:
Payload.$: "$"
Retry:
- ErrorEquals:
- Lambda.ServiceException
- Lambda.AWSLambdaException
- Lambda.SdkClientException
IntervalSeconds: 2
MaxAttempts: 6
BackoffRate: 2
Next: Wait
Wait:
Type: Wait
Seconds: 5
Next: Second function
Second function:
Type: Task
Resource: !GetAtt secondFunction.Arn
OutputPath: "$.Payload"
Parameters:
Payload.$: "$"
Retry:
- ErrorEquals:
- Lambda.ServiceException
- Lambda.AWSLambdaException
- Lambda.SdkClientException
IntervalSeconds: 2
MaxAttempts: 6
BackoffRate: 2
End: true
functions:
firstFunction:
handler: src/functions/first.handler
secondFunction:
handler: src/functions/second.handler
If you enjoyed this post and want to see more, follow me on Twitter at @TastefulElk where I frequently write about serverless tech, AWS, and developer productivity! 👋
Posted on August 11, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.