State machines with Lambda

Ok, so, Lambda is good. It's great, in fact. It is amazing at doing one thing well, and that is running the compute for a nano or microservice. But as we already know, serverless applications are more than just one disparate microservice: they can be made up of tens or hundreds even—and that's not forgetting the messaging and event sourcing systems that help with the flow of communication between other interfaces and compute. How do we make sure a transaction can traverse through this fruit salad of services, end to end, to ensure that the output is successful and errors are handled? This is where state machines are super helpful. 

AWS Step Functions provides state machines that can orchestrate serverless applications and enable the workflow logic that a transaction would need in a modern microservice application. In this section, we'll cover some core concepts and explain how you can get started with building your own state machines using Lambda. We'll be keeping it fairly high level because this can be quite a deep topic. 

Here's an example of how a state machine can be visualized through the console. Yes, it's the example that we worked with in the previous sections, but with more functionality.

The following diagram is representative of the state machine or workflow:

Graphic representation of our state machine, found in the Step Functions console

In order to understand what is going on here, let's kick off with a few key concepts. The entire workflow shown in the preceding diagram can be defined in JSON, which allows you to store infrastructure as code in source control. CloudFormation is also supported for defining and declaring Step Functions resources. Every run through of a workflow is called an execution, and we can kick those off using the CLI, SDKs, or Step Functions API. You can execute one or ten thousand state machine executions and they will all run in parallel, and all of them can be monitored from the console.

There are seven different state types that an execution can be in. Each type has its own configurable parameters that you can choose in the console or include in your JSON definition. Here are the seven different states:

  • A task is one unit of work. The resource we've chosen to do this work is a Lambda function:
"ExtractPhotoMetadata":{
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:photosMetadata",
"Next": "ProcessPhoto"
}
  • A choice is where you can add logic to branch out the tasks in an execution. You might decide to do one thing instead of another, depending on the output of a Lambda function.
  • Parallel execution is when you can fork and run two or more tasks in parallel, and then join their output for the next change in state. In the following example, we are adding our metadata to DynamoDB at the same time as another function is running to perform image recognition to classify what is in the photo:
"ProcessPhoto": {
"Type": "Parallel",
"Next": "MoveProcessedPhoto",
"Branches": [{
"StartAt": "PersistMetadata",
"States": {
"PersistMetadata": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:savePhotoMetadata",
"End": true
}}}, {
"StartAt": "PerformImageRecognition",
"States": {
"PerformImageRecognition": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:classifyImage",
"End": true
}}}]}
  • A wait state is an artificial delay of a trivial length. You might use this when we're waiting for another service to start up before polling. We don't have a reason for this state in our example, so let's move on. 
  • A failure state stops the execution and flags it as a failure. This is like a script exiting with a non-zero condition. In our example, we want to exit if our function checking the file types returns an error for an unsupported type:
"CheckFileType": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:checkPhotoFileType",
"Next": "ExtractPhotoMetadata",
"Catch": [ {
"ErrorEquals": ["UnsupportedType"],
"Next": "UnsupportedType"
}]
},
"UnsupportedType": {
"Type": "Fail",
"Cause": "UnsupportedPhotoType",
"Error": "File type not a supported photo"
}
  • Conversely, a succeed state is when an execution stops with a successful outcome. You can specify this in any state by using the end field:
"End": true
  • Finally, a pass state is when the input is simply passed to its output without doing any work on the data. We don't have any of these in our example.

Where does the state exist during transitions? Well, it lives in the machine, that is, in JSON objects that are passed from state to state.

In Chapter 7, Serverless Framework, we'll introduce an application framework that can simplify the job of creating and maintaining state machines in code. Step Functions also integrates with other services. We'll find out more about this in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.196.146