Gathering detailed insights and metrics for serverless-step-functions
Gathering detailed insights and metrics for serverless-step-functions
Gathering detailed insights and metrics for serverless-step-functions
Gathering detailed insights and metrics for serverless-step-functions
@types/serverless-step-functions
TypeScript definitions for serverless-step-functions
@sei-atl/step-function-executor
Use this utility to execute serverless Step Functions locally!
serverless-step-functions-offline-async
A fork of serverless-step-functions-offline with added support for async lambda handlers.
serverless-step-functions-local
Run AWS step functions offline with Serverless
AWS Step Functions plugin for Serverless Framework ⚡️
npm install serverless-step-functions
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
1,034 Stars
921 Commits
208 Forks
20 Watching
3 Branches
100 Contributors
Updated on 25 Nov 2024
Minified
Minified + Gzipped
JavaScript (100%)
Cumulative downloads
Total Downloads
Last day
-4.2%
22,887
Compared to previous day
Last week
5.7%
119,667
Compared to previous week
Last month
8%
495,198
Compared to previous month
Last year
4%
6,289,431
Compared to previous year
6
1
This is the Serverless Framework plugin for AWS Step Functions.
Serverless Framework v2.32.0 or later is required.
Run npm install
in your Serverless project.
$ npm install --save-dev serverless-step-functions
Add the plugin to your serverless.yml file
1plugins: 2 - serverless-step-functions
Specify your state machine definition using Amazon States Language in a definition
statement in serverless.yml. You can use CloudFormation intrinsic functions such as Ref
and Fn::GetAtt
to reference Lambda functions, SNS topics, SQS queues and DynamoDB tables declared in the same serverless.yml
. Since Ref
returns different things (ARN, ID, resource name, etc.) depending on the type of CloudFormation resource, please refer to this page to see whether you need to use Ref
or Fn::GetAtt
.
Alternatively, you can also provide the raw ARN, or SQS queue URL, or DynamoDB table name as a string. If you need to construct the ARN by hand, then we recommend to use the serverless-pseudo-parameters plugin together to make your life easier.
In addition, if you want to reference a DynamoDB table managed by an external CloudFormation Stack, as long as that table name is exported as an output from that stack, it can be referenced by importing it using Fn::ImportValue
. See the ddbtablestepfunc
Step Function definition below for an example.
1functions: 2 hello: 3 handler: handler.hello 4 5stepFunctions: 6 stateMachines: 7 hellostepfunc1: 8 events: 9 - http: 10 path: gofunction 11 method: GET 12 - schedule: 13 rate: rate(10 minutes) 14 enabled: true 15 input: 16 key1: value1 17 key2: value2 18 stageParams: 19 stage: dev 20 name: myStateMachine 21 definition: 22 Comment: "A Hello World example of the Amazon States Language using an AWS Lambda Function" 23 StartAt: HelloWorld1 24 States: 25 HelloWorld1: 26 Type: Task 27 Resource: 28 Fn::GetAtt: [hello, Arn] 29 End: true 30 dependsOn: CustomIamRole 31 tags: 32 Team: Atlantis 33 alarms: 34 topics: 35 ok: arn:aws:sns:us-east-1:1234567890:NotifyMe 36 alarm: arn:aws:sns:us-east-1:1234567890:NotifyMe 37 insufficientData: arn:aws:sns:us-east-1:1234567890:NotifyMe 38 metrics: 39 - executionsTimedOut 40 - executionsFailed 41 - executionsAborted 42 - metric: executionThrottled 43 treatMissingData: breaching # overrides below default 44 - executionsSucceeded 45 treatMissingData: ignore # optional 46 hellostepfunc2: 47 definition: 48 StartAt: HelloWorld2 49 States: 50 HelloWorld2: 51 Type: Task 52 Resource: 53 Fn::GetAtt: [hello, Arn] 54 End: true 55 ddbtablestepfunc: 56 definition: 57 Comment: Demonstrates how to reference a DynamoDB Table Name exported from an external CloudFormation Stack 58 StartAt: ImportDDBTableName 59 States: 60 ImportDDBTableName: 61 Type: Task 62 Resource: "arn:aws:states:::dynamodb:updateItem" 63 Parameters: 64 TableName: 65 Fn::ImportValue: MyExternalStack:ToDoTable:Name # imports a table name from an external stack 66 Key: 67 id: 68 S.$: "$.todoId" 69 UpdateExpression: "SET #status = :updatedStatus" 70 ExpressionAttributeNames: 71 "#status": status 72 ExpressionAttributeValues: 73 ":updatedStatus": 74 S: DONE 75 End: true 76 dependsOn: 77 - DynamoDBTable 78 - KinesisStream 79 - CustomIamRole 80 tags: 81 Team: Atlantis 82 activities: 83 - myTask 84 - yourTask 85 validate: true # enable pre-deployment definition validation (disabled by default) 86 87plugins: 88 - serverless-step-functions 89 - serverless-pseudo-parameters
In the example above, notice that we used Fn::GetAtt: [hello, Arn]
to get the ARN for the hello
function defined earlier. This means you don't have to know how the Serverless
framework converts these local names to CloudFormation logical IDs (e.g. hello-world
becomes HelloDashworldLambdaFunction
).
However, if you prefer to work with logical IDs, you can. You can also express the above Fn::GetAtt
function as Fn::GetAtt: [HelloLambdaFunction, Arn]
. If you're unfamiliar with the convention the Serverless
framework uses, then the easiest thing to do is to first run sls package
then look in the .serverless
folder for the generated CloudFormation template. Here you can find the logical resource names for the functions you want to reference.
In case you need to interpolate a specific stage or service layer variable as the
stateMachines name you can add a name
property to your yaml.
1service: messager 2 3functions: 4 sendMessage: 5 handler: handler.sendMessage 6 7stepFunctions: 8 stateMachines: 9 sendMessageFunc: 10 name: sendMessageFunc-${self:custom.service}-${opt:stage} 11 definition: 12 <your definition> 13 14plugins: 15 - serverless-step-functions
You can use a custom logical id that is only unique within the stack as opposed to the name that needs to be unique globally. This can make referencing the state machine easier/simpler because you don't have to duplicate the interpolation logic everywhere you reference the state machine.
1service: messager 2 3functions: 4 sendMessage: 5 handler: handler.sendMessage 6 7stepFunctions: 8 stateMachines: 9 sendMessageFunc: 10 id: SendMessageStateMachine 11 name: sendMessageFunc-${self:custom.service}-${opt:stage} 12 definition: 13 <your definition> 14 15plugins: 16 - serverless-step-functions
You can then Ref: SendMessageStateMachine
in various parts of CloudFormation or serverless.yml
If your state machine depends on another resource defined in your serverless.yml
then you can add a dependsOn
field to the state machine definition
. This would add the DependsOn
clause to the generated CloudFormation template.
This dependsOn
field can be either a string, or an array of strings.
1stepFunctions: 2 stateMachines: 3 myStateMachine: 4 dependsOn: myDB 5 6 myOtherStateMachine: 7 dependsOn: 8 - myOtherDB 9 - myStream
There are some practical cases when you would like to prevent state machine from deletion on stack delete or update. This can be achieved by adding retain
property to the state machine section.
1stepFunctions: 2 stateMachines: 3 myStateMachine: 4 retain: true
Configuring in such way adds "DeletionPolicy" : "Retain"
to the state machine within CloudFormation template.
It's common practice to want to monitor the health of your state machines and be alerted when something goes wrong. You can either:
alarms
configuration from this plugin, which gives you an opinionated set of default alarms (see below)1stepFunctions: 2 stateMachines: 3 myStateMachine: 4 alarms: 5 topics: 6 ok: arn:aws:sns:us-east-1:1234567890:NotifyMe 7 alarm: arn:aws:sns:us-east-1:1234567890:NotifyMe 8 insufficientData: arn:aws:sns:us-east-1:1234567890:NotifyMe 9 metrics: 10 - executionsTimedOut 11 - executionsFailed 12 - executionsAborted 13 - executionThrottled 14 - executionsSucceeded 15 treatMissingData: missing
Both topics
and metrics
are required properties. There are 4 supported metrics, each map to the CloudWatch Metrics that Step Functions publishes for your executions.
You can configure how the CloudWatch Alarms should treat missing data:
missing
(AWS default): The alarm does not consider missing data points when evaluating whether to change state.ignore
: The current alarm state is maintained.breaching
: Missing data points are treated as breaching the threshold.notBreaching
: Missing data points are treated as being within the threshold.For more information, please refer to the official documentation.
The generated CloudWatch alarms would have the following configurations:
1namespace: 'AWS/States' 2metric: <ExecutionsTimedOut | ExecutionsFailed | ExecutionsAborted | ExecutionThrottled> 3threshold: 1 4period: 60 5evaluationPeriods: 1 6ComparisonOperator: GreaterThanOrEqualToThreshold 7Statistic: Sum 8treatMissingData: <missing (default) | ignore | breaching | notBreaching> 9Dimensions: 10 - Name: StateMachineArn 11 Value: <ArnOfTheStateMachine>
You can also override the default treatMissingData
setting for a particular alarm by specifying an override:
1alarms: 2 topics: 3 ok: arn:aws:sns:us-east-1:1234567890:NotifyMe 4 alarm: arn:aws:sns:us-east-1:1234567890:NotifyMe 5 insufficientData: arn:aws:sns:us-east-1:1234567890:NotifyMe 6 metrics: 7 - executionsTimedOut 8 - executionsFailed 9 - executionsAborted 10 - metric: executionThrottled 11 treatMissingData: breaching # override 12 - executionsSucceeded 13 treatMissingData: ignore # default
By default, the CloudFormation assigns names to the alarms based on the CloudFormation stack and the resource logical Id, and in some cases and these names could be confusing.
To use custom names to the alarms add nameTemplate
property in the alarms
object.
example:
1service: myservice 2 3plugins: 4 - serverless-step-functions 5 6stepFunctions: 7 stateMachines: 8 main-workflow: 9 name: main 10 alarms: 11 nameTemplate: $[stateMachineName]-$[cloudWatchMetricName]-alarm 12 topics: 13 alarm: !Ref AwsAlertsGenericAlarmTopicAlarm 14 metrics: 15 - executionsFailed 16 - executionsAborted 17 - executionsTimedOut 18 - executionThrottled 19 treatMissingData: ignore 20 definition: ${file(./step-functions/main.asl.yaml)}
Supported variables to the nameTemplate
property:
stateMachineName
metricName
cloudWatchMetricName
To overwrite the alarm name for a specific metric, add the alarmName
property in the metric object.
1service: myservice 2 3plugins: 4 - serverless-step-functions 5 6stepFunctions: 7 stateMachines: 8 main-workflow: 9 name: main 10 alarms: 11 nameTemplate: $[stateMachineName]-$[cloudWatchMetricName]-alarm 12 topics: 13 alarm: !Ref AwsAlertsGenericAlarmTopicAlarm 14 metrics: 15 - metric: executionsFailed 16 alarmName: mycustom-name-${self:stage.region}-Failed-alarm 17 - executionsAborted 18 - executionsTimedOut 19 - executionThrottled 20 treatMissingData: ignore 21 definition: ${file(./step-functions/main.asl.yaml)}
You can monitor the execution state of your state machines via CloudWatch Events. It allows you to be alerted when the status of your state machine changes to ABORTED
, FAILED
, RUNNING
, SUCCEEDED
or TIMED_OUT
.
You can configure CloudWatch Events to send notification to a number of targets. Currently this plugin supports sns
, sqs
, kinesis
, firehose
, lambda
and stepFunctions
.
To configure status change notifications to your state machine, you can add a notifications
like below:
1stepFunctions: 2 stateMachines: 3 hellostepfunc1: 4 name: test 5 definition: 6 ... 7 notifications: 8 ABORTED: 9 - sns: SNS_TOPIC_ARN 10 - sqs: SQS_TOPIC_ARN 11 - sqs: # for FIFO queues, which requires you to configure the message group ID 12 arn: SQS_TOPIC_ARN 13 messageGroupId: 12345 14 - lambda: LAMBDA_FUNCTION_ARN 15 - kinesis: KINESIS_STREAM_ARN 16 - kinesis: 17 arn: KINESIS_STREAM_ARN 18 partitionKeyPath: $.id # used to choose the parition key from payload 19 - firehose: FIREHOSE_STREAM_ARN 20 - stepFunctions: STATE_MACHINE_ARN 21 FAILED: 22 ... # same as above 23 ... # other status
As you can see from the above example, you can configure different notification targets for each type of status change. If you want to configure the same targets for multiple status changes, then consider using YML anchors to keep your YML succinct.
CloudFormation intrinsic functions such as Ref
and Fn::GetAtt
are supported.
When setting up a notification target against a FIFO SQS queue, the queue must enable the content-based deduplication option and you must configure the messageGroupId
.
To implement a blue-green deployment with Step Functions you need to reference the exact versions of the functions.
To do this, you can specify useExactVersion: true
in the state machine.
1stepFunctions: 2 stateMachines: 3 hellostepfunc1: 4 useExactVersion: true 5 definition: 6 ...
By default, your state machine definition will be validated during deployment by StepFunctions. This can be cumbersome when developing because you have to upload your service for every typo in your definition. In order to go faster, you can enable pre-deployment validation using asl-validator which should detect most of the issues (like a missing state property).
1stepFunctions: 2 validate: true
Disables the generation of outputs in the CloudFormation Outputs section. If you define many state machines in serverless.yml you may reach the CloudFormation limit of 60 outputs. If you define noOutput: true
then this plugin will not generate outputs automatically.
1stepFunctions: 2 noOutput: true
At re:invent 2019, AWS introduced Express Workflows as a cheaper, more scalable alternative (but with a cut-down set of features). See this page for differences between standard and express workflows.
To declare an express workflow, specify type
as EXPRESS
and you can specify the logging configuration:
1stepFunctions: 2 stateMachines: 3 hellostepfunc1: 4 type: EXPRESS 5 loggingConfig: 6 level: ERROR 7 includeExecutionData: true 8 destinations: 9 - Fn::GetAtt: [MyLogGroup, Arn]
You can enable CloudWatch Logs for standard Step Functions, the syntax is exactly like with Express Workflows.
1stepFunctions: 2 stateMachines: 3 hellostepfunc1: 4 loggingConfig: 5 level: ERROR 6 includeExecutionData: true 7 destinations: 8 - Fn::GetAtt: [MyLogGroup, Arn]
You can enable X-Ray for your state machine, specify tracingConfig
as shown below.
1stepFunctions: 2 stateMachines: 3 hellostepfunc1: 4 tracingConfig: 5 enabled: true
Please keep this gotcha in mind if you want to reference the name
from the resources
section. To generate Logical ID for CloudFormation, the plugin transforms the specified name in serverless.yml based on the following scheme.
-
into Dash_
into UnderscoreIf you want to use variables system in name statement, you can't put the variables as a prefix like this:${self:service}-${opt:stage}-myStateMachine
since the variables are transformed within Output section, as a result, the reference will be broken.
The correct sample is here.
1stepFunctions: 2 stateMachines: 3 myStateMachine: 4 name: myStateMachine-${self:service}-${opt:stage} 5... 6 7resources: 8 Outputs: 9 myStateMachine: 10 Value: 11 Ref: MyStateMachineDash${self:service}Dash${opt:stage}
To create HTTP endpoints as Event sources for your StepFunctions statemachine
This setup specifies that the hello state machine should be run when someone accesses the API gateway at hello via a GET request.
Here's an example:
1stepFunctions: 2 stateMachines: 3 hello: 4 events: 5 - http: 6 path: hello 7 method: GET 8 definition:
Here You can define an POST endpoint for the path posts/create.
1stepFunctions: 2 stateMachines: 3 hello: 4 events: 5 - http: 6 path: posts/create 7 method: POST 8 definition:
Step Functions have custom actions like DescribeExecution or StopExecution to fetch and control them. You can use custom actions like this:
1stepFunctions: 2 stateMachines: 3 start: 4 events: 5 - http: 6 path: action/start 7 method: POST 8 definition: 9 ... 10 status: 11 events: 12 - http: 13 path: action/status 14 method: POST 15 action: DescribeExecution 16 definition: 17 ... 18 stop: 19 events: 20 - http: 21 path: action/stop 22 method: POST 23 action: StopExecution 24 definition: 25 ...
Request template is not used when action is set because there're a bunch of actions. However if you want to use request template you can use Customizing request body mapping templates.
The plugin would generate an IAM Role for you by default. However, if you wish to use an IAM role that you have provisioned separately, then you can override the IAM Role like this:
1stepFunctions: 2 stateMachines: 3 hello: 4 events: 5 - http: 6 path: posts/create 7 method: POST 8 iamRole: arn:aws:iam::<accountId>:role/<roleName> 9 definition:
You can share the same API Gateway between multiple projects by referencing its REST API ID and Root Resource ID in serverless.yml as follows:
1service: service-name 2provider: 3 name: aws 4 apiGateway: 5 # REST API resource ID. Default is generated by the framework 6 restApiId: xxxxxxxxxx 7 # Root resource, represent as / path 8 restApiRootResourceId: xxxxxxxxxx 9 10functions: 11 ...
If your application has many nested paths, you might also want to break them out into smaller services.
However, Cloudformation will throw an error if we try to generate an existing path resource. To avoid that, we reference the resource ID:
1service: service-a 2provider: 3 apiGateway: 4 restApiId: xxxxxxxxxx 5 restApiRootResourceId: xxxxxxxxxx 6 # List of existing resources that were created in the REST API. This is required or the stack will be conflicted 7 restApiResources: 8 /users: xxxxxxxxxx 9 10functions: 11 ...
Now we can define endpoints using existing API Gateway ressources
1stepFunctions: 2 stateMachines: 3 hello: 4 events: 5 - http: 6 path: users/create 7 method: POST
To set CORS configurations for your HTTP endpoints, simply modify your event configurations as follows:
1stepFunctions: 2 stateMachines: 3 hello: 4 events: 5 - http: 6 path: posts/create 7 method: POST 8 cors: true 9 definition:
Setting cors to true assumes a default configuration which is equivalent to:
1stepFunctions: 2 stateMachines: 3 hello: 4 events: 5 - http: 6 path: posts/create 7 method: POST 8 cors: 9 origin: '*' 10 headers: 11 - Content-Type 12 - X-Amz-Date 13 - Authorization 14 - X-Api-Key 15 - X-Amz-Security-Token 16 - X-Amz-User-Agent 17 allowCredentials: false 18 definition:
Configuring the cors property sets Access-Control-Allow-Origin, Access-Control-Allow-Headers, Access-Control-Allow-Methods,Access-Control-Allow-Credentials headers in the CORS preflight response. To enable the Access-Control-Max-Age preflight response header, set the maxAge property in the cors object:
1stepFunctions: 2 stateMachines: 3 SfnApiGateway: 4 events: 5 - http: 6 path: /playground/start 7 method: post 8 cors: 9 origin: '*' 10 maxAge: 86400
If you want to require that the caller submit the IAM user's access keys in order to be authenticated to invoke your Lambda Function, set the authorizer to AWS_IAM as shown in the following example:
1stepFunctions: 2 stateMachines: 3 hello: 4 events: 5 - http: 6 path: posts/create 7 method: POST 8 authorizer: aws_iam 9 definition:
Custom Authorizers allow you to run an AWS Lambda Function before your targeted AWS Lambda Function. This is useful for Microservice Architectures or when you simply want to do some Authorization before running your business logic.
You can enable Custom Authorizers for your HTTP endpoint by setting the Authorizer in your http event to another function in the same service, as shown in the following example:
1stepFunctions: 2 stateMachines: 3 hello: 4 - http: 5 path: posts/create 6 method: post 7 authorizer: authorizerFunc 8 definition:
If the Authorizer function does not exist in your service but exists in AWS, you can provide the ARN of the Lambda function instead of the function name, as shown in the following example:
1stepFunctions: 2 stateMachines: 3 hello: 4 - http: 5 path: posts/create 6 method: post 7 authorizer: xxx:xxx:Lambda-Name 8 definition:
Auto-created Authorizer is convenient for conventional setup. However, when you need to define your custom Authorizer, or use COGNITO_USER_POOLS authorizer with shared API Gateway, it is painful because of AWS limitation. Sharing Authorizer is a better way to do.
1stepFunctions: 2 stateMachines: 3 createUser: 4 ... 5 events: 6 - http: 7 path: /users 8 ... 9 authorizer: 10 # Provide both type and authorizerId 11 type: COGNITO_USER_POOLS # TOKEN, CUSTOM or COGNITO_USER_POOLS, same as AWS Cloudformation documentation 12 authorizerId: 13 Ref: ApiGatewayAuthorizer # or hard-code Authorizer ID 14 # [Optional] you can also specify the OAuth scopes for Cognito 15 scopes: 16 - scope1 17 ...
The plugin generates default body mapping templates for application/json
and application/x-www-form-urlencoded
content types. The default template would pass the request body as input to the state machine. If you need access to other contextual information about the HTTP request such as headers, path parameters, etc. then you can also use the lambda_proxy
request template like this:
1stepFunctions: 2 stateMachines: 3 hello: 4 events: 5 - http: 6 path: posts/create 7 method: POST 8 request: 9 template: lambda_proxy
This would generate the normal LAMBDA_PROXY template used for API Gateway integration with Lambda functions.
If you'd like to add content types or customize the default templates, you can do so by including your custom API Gateway request mapping template in serverless.yml
like so:
1stepFunctions: 2 stateMachines: 3 hello: 4 events: 5 - http: 6 path: posts/create 7 method: POST 8 request: 9 template: 10 application/json: | 11 #set( $body = $util.escapeJavaScript($input.json('$')) ) 12 #set( $name = $util.escapeJavaScript($input.json('$.data.attributes.order_id')) ) 13 { 14 "input": "$body", 15 "name": "$name", 16 "stateMachineArn":"arn:aws:states:#{AWS::Region}:#{AWS::AccountId}:stateMachine:processOrderFlow-${opt:stage}" 17 } 18 name: processOrderFlow-${opt:stage} 19 definition:
If you'd like to add custom headers in the HTTP response, or customize the default response template (which just returns the response from Step Function's StartExecution API), then you can do so by including your custom headers and API Gateway response mapping template in serverless.yml
like so:
1stepFunctions: 2 stateMachines: 3 hello: 4 events: 5 - http: 6 path: posts/create 7 method: POST 8 response: 9 headers: 10 Content-Type: "'application/json'" 11 X-Application-Id: "'my-app'" 12 template: 13 application/json: | 14 { 15 "status": 200, 16 "info": "OK" 17 } 18 definition:
You can input an value as json in request body, the value is passed as the input value of your statemachine
$ curl -XPOST https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/posts/create -d '{"foo":"bar"}'
You can specify a list of API keys to be used by your service Rest API by adding an apiKeys array property to the apiGateway subsection of the provider object in serverless.yml. You'll also need to explicitly specify which endpoints are private and require one of the api keys to be included in the request by adding a private boolean property to the http event object you want to set as private. API Keys are created globally, so if you want to deploy your service to different stages make sure your API key contains a stage variable as defined below. When using API keys, you can optionally define usage plan quota and throttle, using usagePlan object.
Here's an example configuration for setting API keys for your service Rest API:
1service: my-service 2provider: 3 name: aws 4 apiGateway: 5 apiKeys: 6 - myFirstKey 7 - ${opt:stage}-myFirstKey 8 - ${env:MY_API_KEY} # you can hide it in a serverless variable 9 usagePlan: 10 quota: 11 limit: 5000 12 offset: 2 13 period: MONTH 14 throttle: 15 burstLimit: 200 16 rateLimit: 100 17functions: 18 hello: 19 handler: handler.hello 20 21 stepFunctions: 22 stateMachines: 23 statemachine1: 24 name: ${self:service}-${opt:stage}-statemachine1 25 events: 26 - http: 27 path: /hello 28 method: post 29 private: true 30 definition: 31 Comment: "A Hello World example of the Amazon States Language using an AWS Lambda Function" 32 StartAt: HelloWorld1 33 States: 34 HelloWorld1: 35 Type: Task 36 Resource: 37 Fn::GetAtt: [hello, Arn] 38 End: true 39 40 41 plugins: 42 - serverless-step-functions 43 - serverless-pseudo-parameters
Please note that those are the API keys names, not the actual values. Once you deploy your service, the value of those API keys will be auto generated by AWS and printed on the screen for you to use. The values can be concealed from the output with the --conceal deploy option.
Clients connecting to this Rest API will then need to set any of these API keys values in the x-api-key header of their request. This is only necessary for functions where the private property is set to true.
To use request schema validation with API gateway, add the JSON Schema for your content type. Since JSON Schema is represented in JSON, it's easier to include it from a file.
1stepFunctions: 2 stateMachines: 3 create: 4 events: 5 - http: 6 path: posts/create 7 method: post 8 request: 9 schemas: 10 application/json: ${file(create_request.json)}
In addition, you can also customize created model with name and description properties.
1stepFunctions: 2 stateMachines: 3 create: 4 events: 5 - http: 6 path: posts/create 7 method: post 8 request: 9 schemas: 10 application/json: 11 schema: ${file(create_request.json)} 12 name: PostCreateModel 13 description: 'Validation model for Creating Posts'
To reuse the same model across different events, you can define global models on provider level. In order to define global model you need to add its configuration to provider.apiGateway.request.schemas
. After defining a global model, you can use it in the event by referencing it by the key. Provider models are created for application/json content type.
1provider: 2 ... 3 apiGateway: 4 request: 5 schemas: 6 post-create-model: 7 name: PostCreateModel 8 schema: ${file(api_schema/post_add_schema.json)} 9 description: "A Model validation for adding posts" 10 11stepFunctions: 12 stateMachines: 13 create: 14 events: 15 - http: 16 path: posts/create 17 method: post 18 request: 19 schemas: 20 application/json: post-create-model
A sample schema contained in create_request.json
might look something like this:
1{ 2 "definitions": {}, 3 "$schema": "http://json-schema.org/draft-04/schema#", 4 "type": "object", 5 "title": "The Root Schema", 6 "required": ["username"], 7 "properties": { 8 "username": { 9 "type": "string", 10 "title": "The Foo Schema", 11 "default": "", 12 "pattern": "^[a-zA-Z0-9]+$" 13 } 14 } 15}
NOTE: schema validators are only applied to content types you specify. Other content types are not blocked. Currently, API Gateway supports JSON Schema draft-04.
The following config will attach a schedule event and causes the stateMachine crawl
to be called every 2 hours. The configuration allows you to attach multiple schedules to the same stateMachine. You can either use the rate
or cron
syntax. Take a look at the AWS schedule syntax documentation for more details.
1stepFunctions: 2 stateMachines: 3 crawl: 4 events: 5 - schedule: rate(2 hours) 6 - schedule: cron(0 12 * * ? *) 7 definition:
Note: schedule
events are enabled by default.
This will create and attach a schedule event for the aggregate
stateMachine which is disabled. If enabled it will call
the aggregate
stateMachine every 10 minutes.
1stepFunctions: 2 stateMachines: 3 aggregate: 4 events: 5 - schedule: 6 rate: rate(10 minutes) 7 enabled: false 8 input: 9 key1: value1 10 key2: value2 11 stageParams: 12 stage: dev 13 - schedule: 14 rate: cron(0 12 * * ? *) 15 enabled: false 16 inputPath: '$.stageVariables'
Name and Description can be specified for a schedule event. These are not required properties.
1events: 2 - schedule: 3 name: your-scheduled-rate-event-name 4 description: 'your scheduled rate event description' 5 rate: rate(2 hours)
By default, the plugin will create a new IAM role that allows AWS Events to start your state machine. Note that this role is different than the role assumed by the state machine. You can specify your own role instead (it must allow events.amazonaws.com
to assume it, and it must be able to run states:StartExecution
on your state machine):
1events: 2 - schedule: 3 rate: rate(2 hours) 4 role: arn:aws:iam::xxxxxxxx:role/yourRole
You can specify input values to the Lambda function.
1stepFunctions: 2 stateMachines: 3 stateMachineScheduled: 4 events: 5 - schedule: 6 rate: cron(30 12 ? * 1-5 *) 7 inputTransformer: 8 inputPathsMap: 9 time: '$.time' 10 stage: '$.stageVariables' 11 inputTemplate: '{"time": <time>, "stage" : <stage> }' 12 definition: 13 ...
AWS has account-wide limits on the number of AWS::Event::Rule
triggers per bus (300 events), and all Lambda schedules go into a single bus with no way to override it. This can lead to a situation where large projects hit the limit with no ability to schedule more events.
However, AWS::Scheduler::Schedule
has much higher limits (1,000,000 events), and is configured identically. method
can be set in order to migrate to this trigger type seamlessly. It also allows you to specify a timezone to run your event based on local time.
1stepFunctions: 2 stateMachines: 3 stateMachineScheduled: 4 events: 5 - schedule: 6 method: scheduler 7 rate: cron(30 12 ? * 1-5 *) 8 enabled: true 9 timezone: America/New_York 10 definition: 11 ...
This will enable your Statemachine to be called by an EC2 event rule. Please check the page of Event Types for CloudWatch Events.
1stepFunctions: 2 stateMachines: 3 first: 4 events: 5 - cloudwatchEvent: 6 event: 7 source: 8 - "aws.ec2" 9 detail-type: 10 - "EC2 Instance State-change Notification" 11 detail: 12 state: 13 - pending 14 definition: 15 ...
You can alternatively use EventBridge:
1stepFunctions: 2 stateMachines: 3 first: 4 events: 5 - eventBridge: 6 event: 7 source: 8 - "aws.ec2" 9 detail-type: 10 - "EC2 Instance State-change Notification" 11 detail: 12 state: 13 - pending 14 definition: 15 ...
All the configurations in this section applies to both cloudwatchEvent
and eventBridge
.
Note: cloudwatchEvent
and eventBridge
events are enabled by default.
This will create and attach a disabled cloudwatchEvent
event for the myCloudWatch
statemachine.
1stepFunctions: 2 stateMachines: 3 cloudwatchEvent: 4 events: 5 - cloudwatchEvent: 6 event: 7 source: 8 - "aws.ec2" 9 detail-type: 10 - "EC2 Instance State-change Notification" 11 detail: 12 state: 13 - pending 14 enabled: false 15 definition: 16 ...
You can specify input values to the Lambda function.
1stepFunctions: 2 stateMachines: 3 cloudwatchEvent: 4 events: 5 - cloudwatchEvent: 6 event: 7 source: 8 - "aws.ec2" 9 detail-type: 10 - "EC2 Instance State-change Notification" 11 detail: 12 state: 13 - pending 14 input: 15 key1: value1 16 key2: value2 17 stageParams: 18 stage: dev 19 - cloudwatchEvent: 20 event: 21 source: 22 - "aws.ec2" 23 detail-type: 24 - "EC2 Instance State-change Notification" 25 detail: 26 state: 27 - pending 28 inputPath: '$.stageVariables' 29 - cloudwatchEvent: 30 event: 31 source: 32 - "aws.ec2" 33 detail-type: 34 - "EC2 Instance State-change Notification" 35 detail: 36 state: 37 - pending 38 inputTransformer: 39 inputPathsMap: 40 stage: '$.stageVariables' 41 inputTemplate: '{ "stage": <stage> }' 42 definition: 43 ...
You can also specify a CloudWatch Event description.
1stepFunctions: 2 stateMachines: 3 cloudwatchEvent: 4 events: 5 - cloudwatchEvent: 6 description: 'CloudWatch Event triggered on EC2 Instance pending state' 7 event: 8 source: 9 - "aws.ec2" 10 detail-type: 11 - "EC2 Instance State-change Notification" 12 detail: 13 state: 14 - pending 15 definition: 16 ...
You can also specify a CloudWatch Event name. Keep in mind that the name must begin with a letter; contain only ASCII letters, digits, and hyphens; and not end with a hyphen or contain two consecutive hyphens. More infomation here.
1stepFunctions: 2 stateMachines: 3 cloudwatchEvent: 4 events: 5 - cloudwatchEvent: 6 name: 'my-cloudwatch-event-name' 7 event: 8 source: 9 - "aws.ec2" 10 detail-type: 11 - "EC2 Instance State-change Notification" 12 detail: 13 state: 14 - pending 15 definition: 16 ...
You can also specify a CloudWatch Event RoleArn. The Amazon Resource Name (ARN) of the role that is used for target invocation.
Required: No
1stepFunctions: 2 stateMachines: 3 cloudwatchEvent: 4 events: 5 - cloudwatchEvent: 6 name: 'my-cloudwatch-event-name' 7 iamRole: 'arn:aws:iam::012345678910:role/Events-InvokeStepFunctions-Role' 8 event: 9 source: 10 - "aws.ec2" 11 detail-type: 12 - "EC2 Instance State-change Notification" 13 detail: 14 state: 15 - pending 16 definition: 17 ...
You can choose which CloudWatch Event bus:
1stepFunctions: 2 stateMachines: 3 exampleCloudwatchEventStartsMachine: 4 events: 5 - cloudwatchEvent: 6 eventBusName: 'my-custom-event-bus' 7 event: 8 source: 9 - "my.custom.source" 10 detail-type: 11 - "My Event Type" 12 detail: 13 state: 14 - pending 15 definition: 16 ...
You can choose which EventBridge Event bus:
1stepFunctions: 2 stateMachines: 3 exampleEventBridgeEventStartsMachine: 4 events: 5 - eventBridge: 6 eventBusName: 'my-custom-event-bus' 7 event: 8 source: 9 - "my.custom.source" 10 detail-type: 11 - "My Event Type" 12 detail: 13 state: 14 - pending 15 definition: 16 ...
You can configure a target queue to send dead-letter queue events to:
1stepFunctions: 2 stateMachines: 3 exampleEventBridgeEventStartsMachine: 4 events: 5 - eventBridge: 6 eventBusName: 'my-custom-event-bus' 7 event: 8 source: 9 - "my.custom.source" 10 detail-type: 11 - "My Event Type" 12 detail: 13 state: 14 - pending 15 deadLetterConfig: 'arn:aws:sqs:us-east-1:012345678910:my-dlq' # SQS Arn 16 definition: 17 ...
Don't forget to Grant permissions to the dead-letter queue, to do that you may need to have the ARN
of the generated EventBridge Rule
.
In order to get the ARN
you can use intrinsic functions against the logicalId
, this plugin generates logicalIds
following this format:
1`${StateMachineName}EventsRuleCloudWatchEvent${index}`
Given this example 👇
1stepFunctions: 2 stateMachines: 3 hellostepfunc1: # <---- StateMachineName 4 events: 5 - eventBridge: 6 eventBusName: 'my-custom-event-bus' 7 event: 8 source: 9 - "my.custom.source" 10 - eventBridge: 11 eventBusName: 'my-custom-event-bus' 12 event: 13 source: 14 - "my.custom.source" 15 deadLetterConfig: 'arn:aws:sqs:us-east-1:012345678910:my-dlq' 16 name: myStateMachine 17 definition: 18 Comment: "A Hello World example of the Amazon States Language using an AWS Lambda Function" 19 StartAt: HelloWorld1 20 States: 21 HelloWorld1: 22 Type: Task 23 Resource: 24 Fn::GetAtt: [hello, Arn] 25 End: true
Then
1# to get the Arn of the 1st EventBridge rule 2!GetAtt Hellostepfunc1EventsRuleCloudWatchEvent1.Arn 3 4# to get the Arn of the 2nd EventBridge rule 5!GetAtt Hellostepfunc1EventsRuleCloudWatchEvent2.Arn
You can specify tags on each state machine. Additionally any global tags (specified under provider
section in your serverless.yml
) would be merged in as well.
If you don't want for global tags to be merged into your state machine, you can include the inheritGlobalTags
property for your state machine.
1provider: 2 tags: 3 app: myApp 4 department: engineering 5stepFunctions: 6 stateMachines: 7 hellostepfunc1: 8 name: myStateMachine 9 inheritGlobalTags: false 10 tags: 11 score: 42 12 definition: something
As a result, hellostepfunc1
will only have the tag of score: 42
, and not the tags at the provider level
Run sls deploy
, the defined Stepfunctions are deployed.
$ sls invoke stepf --name <stepfunctionname> --data '{"foo":"bar"}'
The IAM roles required to run Statemachine are automatically generated for each state machine in the serverless.yml
, with the IAM role name of StatesExecutionPolicy-<environment>
. These roles are tailored to the services that the state machine integrates with, for example with Lambda the InvokeFunction
is applied. You can also specify a custom ARN directly to the step functions lambda.
Here's an example:
1stepFunctions: 2 stateMachines: 3 hello: 4 role: arn:aws:iam::xxxxxxxx:role/yourRole 5 definition:
It is also possible to use the CloudFormation intrinsic functions to reference resources from elsewhere. This allows for an IAM role to be created, and applied to the state machines all within the serverless file.
The below example shows the policy needed if your step function needs the ability to send a message to an sqs queue. To apply the role either the RoleName can be used as a reference in the state machine, or the role ARN can be used like in the example above. It is important to note that if you want to store your state machine role at a certain path, this must be specified on the Path
property on the new role.
1stepFunctions: 2 stateMachines: 3 hello: 4 role: 5 Fn::GetAtt: ["StateMachineRole", "Arn"] 6 definition: 7 ... 8 9resources: 10 Resources: 11 StateMachineRole: 12 Type: AWS::IAM::Role 13 Properties: 14 RoleName: RoleName 15 Path: /path_of_state_machine_roles/ 16 AssumeRolePolicyDocument: 17 Statement: 18 - Effect: Allow 19 Principal: 20 Service: 21 - states.amazonaws.com 22 Action: 23 - sts:AssumeRole 24 Policies: 25 - PolicyName: statePolicy 26 PolicyDocument: 27 Version: "2012-10-17" 28 Statement: 29 - Effect: Allow 30 Action: 31 - lambda:InvokeFunction 32 Resource: 33 - arn:aws:lambda:lambdaName 34 - Effect: Allow 35 Action: 36 - sqs:SendMessage 37 Resource: 38 - arn:aws:sqs::xxxxxxxx:queueName
The short form of the intrinsic functions (i.e. !Sub
, !Ref
) is not supported at the moment.
Here is serverless.yml sample to specify the stateMachine ARN to environment variables. This makes it possible to trigger your statemachine through Lambda events
1functions: 2 hello: 3 handler: handler.hello 4 environment: 5 statemachine_arn: ${self:resources.Outputs.MyStateMachine.Value} 6 7stepFunctions: 8 stateMachines: 9 hellostepfunc: 10 name: myStateMachine 11 definition: 12 <your definition> 13 14resources: 15 Outputs: 16 MyStateMachine: 17 Description: The ARN of the example state machine 18 Value: 19 Ref: MyStateMachine 20 21plugins: 22 - serverless-step-functions
When you have a large serverless project with lots of state machines your serverless.yml file can grow to a point where it is unmaintainable.
You can split step functions into external files and import them into your serverless.yml file.
There are two ways you can do this:
You can define the entire stateMachines
block in a separate file
and import it in its entirety.
includes/state-machines.yml:
1stateMachines: 2 hellostepfunc1: 3 name: myStateMachine1 4 definition: 5 <your definition> 6 hellostepfunc2: 7 name: myStateMachine2 8 definition: 9 <your definition>
serverless.yml:
1stepFunctions: 2 ${file(includes/state-machines.yml)} 3 4plugins: 5 - serverless-step-functions
You can split up the stateMachines
block into separate files.
includes/state-machine-1.yml:
1name: myStateMachine1 2definition: 3 <your definition>
includes/state-machine-2.yml:
1name: myStateMachine2 2definition: 3 <your definition>
serverless.yml:
1stepFunctions: 2 stateMachines: 3 hellostepfunc1: 4 ${file(includes/state-machine-1.yml)} 5 hellostepfunc2: 6 ${file(includes/state-machine-2.yml)} 7 8plugins: 9 - serverless-step-functions
1functions: 2 hello: 3 handler: handler.hello 4 5stepFunctions: 6 stateMachines: 7 yourWateMachine: 8 definition: 9 Comment: "An example of the Amazon States Language using wait states" 10 StartAt: FirstState 11 States: 12 FirstState: 13 Type: Task 14 Resource: 15 Fn::GetAtt: [hello, Arn] 16 Next: wait_using_seconds 17 wait_using_seconds: 18 Type: Wait 19 Seconds: 10 20 Next: wait_using_timestamp 21 wait_using_timestamp: 22 Type: Wait 23 Timestamp: '2015-09-04T01:59:00Z' 24 Next: wait_using_timestamp_path 25 wait_using_timestamp_path: 26 Type: Wait 27 TimestampPath: "$.expirydate" 28 Next: wait_using_seconds_path 29 wait_using_seconds_path: 30 Type: Wait 31 SecondsPath: "$.expiryseconds" 32 Next: FinalState 33 FinalState: 34 Type: Task 35 Resource: 36 Fn::GetAtt: [hello, Arn] 37 End: true 38plugins: 39 - serverless-step-functions 40 - serverless-pseudo-parameters
1functions: 2 hello: 3 handler: handler.hello 4 5stepFunctions: 6 stateMachines: 7 yourRetryMachine: 8 definition: 9 Comment: "A Retry example of the Amazon States Language using an AWS Lambda Function" 10 StartAt: HelloWorld 11 States: 12 HelloWorld: 13 Type: Task 14 Resource: 15 Fn::GetAtt: [hello, Arn] 16 Retry: 17 - ErrorEquals: 18 - HandledError 19 IntervalSeconds: 1 20 MaxAttempts: 2 21 BackoffRate: 2 22 - ErrorEquals: 23 - States.TaskFailed 24 IntervalSeconds: 30 25 MaxAttempts: 2 26 BackoffRate: 2 27 - ErrorEquals: 28 - States.ALL 29 IntervalSeconds: 5 30 MaxAttempts: 5 31 BackoffRate: 2 32 End: true 33plugins: 34 - serverless-step-functions 35 - serverless-pseudo-parameters
1functions: 2 hello: 3 handler: handler.hello 4 5stepFunctions: 6 stateMachines: 7 yourParallelMachine: 8 definition: 9 Comment: "An example of the Amazon States Language using a parallel state to execute two branches at the same time." 10 StartAt: Parallel 11 States: 12 Parallel: 13 Type: Parallel 14 Next: Final State 15 Branches: 16 - StartAt: Wait 20s 17 States: 18 Wait 20s: 19 Type: Wait 20 Seconds: 20 21 End: true 22 - StartAt: Pass 23 States: 24 Pass: 25 Type: Pass 26 Next: Wait 10s 27 Wait 10s: 28 Type: Wait 29 Seconds: 10 30 End: true 31 Final State: 32 Type: Pass 33 End: true 34plugins: 35 - serverless-step-functions 36 - serverless-pseudo-parameters
1functions: 2 hello: 3 handler: handler.hello 4 5stepFunctions: 6 stateMachines: 7 yourCatchMachine: 8 definition: 9 Comment: "A Catch example of the Amazon States Language using an AWS Lambda Function" 10 StartAt: HelloWorld 11 States: 12 HelloWorld: 13 Type: Task 14 Resource: 15 Fn::GetAtt: [hello, Arn] 16 Catch: 17 - ErrorEquals: ["HandledError"] 18 Next: CustomErrorFallback 19 - ErrorEquals: ["States.TaskFailed"] 20 Next: ReservedTypeFallback 21 - ErrorEquals: ["States.ALL"] 22 Next: CatchAllFallback 23 End: true 24 CustomErrorFallback: 25 Type: Pass 26 Result: "This is a fallback from a custom lambda function exception" 27 End: true 28 ReservedTypeFallback: 29 Type: Pass 30 Result: "This is a fallback from a reserved error code" 31 End: true 32 CatchAllFallback: 33 Type: Pass 34 Result: "This is a fallback from a reserved error code" 35 End: true 36plugins: 37 - serverless-step-functions 38 - serverless-pseudo-parameters
1functions: 2 hello1: 3 handler: handler.hello1 4 hello2: 5 handler: handler.hello2 6 hello3: 7 handler: handler.hello3 8 hello4: 9 handler: handler.hello4 10 11stepFunctions: 12 stateMachines: 13 yourChoiceMachine: 14 definition: 15 Comment: "An example of the Amazon States Language using a choice state." 16 StartAt: FirstState 17 States: 18 FirstState: 19 Type: Task 20 Resource: 21 Fn::GetAtt: [hello, Arn] 22 Next: ChoiceState 23 ChoiceState: 24 Type: Choice 25 Choices: 26 - Variable: "$.foo" 27 NumericEquals: 1 28 Next: FirstMatchState 29 - Variable: "$.foo" 30 NumericEquals: 2 31 Next: SecondMatchState 32 Default: DefaultState 33 FirstMatchState: 34 Type: Task 35 Resource: 36 Fn::GetAtt: [hello2, Arn] 37 Next: NextState 38 SecondMatchState: 39 Type: Task 40 Resource: 41 Fn::GetAtt: [hello3, Arn] 42 Next: NextState 43 DefaultState: 44 Type: Fail 45 Cause: "No Matches!" 46 NextState: 47 Type: Task 48 Resource: 49 Fn::GetAtt: [hello4, Arn] 50 End: true 51plugins: 52 - serverless-step-functions 53 - serverless-pseudo-parameters
1 2functions: 3 entry: 4 handler: handler.entry 5 mapTask: 6 handler: handler.mapTask 7 8stepFunctions: 9 stateMachines: 10 yourMapMachine: 11 definition: 12 Comment: "A Map example of the Amazon States Language using an AWS Lambda Function" 13 StartAt: FirstState 14 States: 15 FirstState: 16 Type: Task 17 Resource: 18 Fn::GetAtt: [entry, Arn] 19 Next: mapped_task 20 mapped_task: 21 Type: Map 22 Iterator: 23 StartAt: FirstMapTask 24 States: 25 FirstMapTask: 26 Type: Task 27 Resource: 28 Fn::GetAtt: [mapTask, Arn] 29 End: true 30 End: true 31 32plugins: 33 - serverless-step-functions
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
7 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 6
Reason
Found 3/11 approved changesets -- score normalized to 2
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
15 existing vulnerabilities detected
Details
Score
Last Scanned on 2024-11-18
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More