Scheduling Future Events with AWS Step Functions
Using the Serverless Framework and the power of AWS Step Functions and AWS Lambda, we create a reusable microservice that is able to execute any business logic at a very precise moment in the future.
Future events
A typical business requirement in a modern application could be something like:
- When a user’s subscription ends one year from now, remind him that his subscription will be extended one week before he is charged.
- When a user signs up to your service send them an email with tips & tricks in the evening 4 days after he signed up.
These scenarios have a lot of similarity and can be simplified to:
When <event> happens, execute <logic> at <moment>.
The event can happen anywhere throughout your application, maybe from a specific API call, or as a trigger from a DynamoDB stream where a specific record got inserted or updated. We will now use AWS Step Functions for waiting until the right moment and performing the required logic.
AWS Step Functions is a serverless function orchestrator that makes it easy to sequence AWS Lambda functions and multiple AWS services into business-critical applications.
Step Function
We make use of the state machine functionality in AWS Step Functions. You can look at a state machine like a definition of states and the description of how you get from one state to another. In our case the state machine will be quite simple with two states: Wait and HandleEvent.
When the state machine starts we wait for a specific moment in the future and then it executes the logic we need.
Serverless
So let’s see how can define this state machine in the Serverless Framework.
In our serverless project, we need to install the serverless-step-functions plugin:
And add the plugin to our serverless.yml
file:
This gives us the ability to define our state machine in serverless.yml
like this:
A couple of things to highlight in this code snippet:
- One of the parameters of the Wait state is
TimestampPath: $.timestamp
. What this means is that we can pass a variable calledtimestamp
to this state and then the state machine will wait to that exact timestamp before going to the next state which is HandleEvent. - The final state is the HandleEvent state, where we reference the arn (Amazon Resource Name) of the
HandleEventLambdaFunction
.
Executing the business logic
In order to make the state machine generic and reusable for different types of events and business logic, the HandleEventLambdaFunction
is implemented like this:
Next to the timestamp
parameter, we also pass lambdaFunctionArn
to the state machine when starting a new execution. This is the arn of the lambda function that actually runs our required business logic. All the HandleEventLambdaFunction
does is invoking this lambda function. The actual business logic could have been implemented in the function above as well, but then we would have to create separate state machines for every type of logic we would like to do.
Executing the State Machine
With all the pieces in place, we can start the state machine with the required inputs:
- In the payload, besides
timestamp
andlambdaFunctionArn
, we pass all other properties that we need for our business logic. These are passed from Wait to HandleEvent automatically and to the final lambda function in line 9 of theHandleEventLambdaFunction
. arn
is the arn of the state machine.name
is the name of the state machine execution, which needs to be unique for 90 days for your AWS account.
We now have all the basic pieces in place for scheduling future events using AWS Step Functions, so let’s have a look at an example.
Tying it all together
Now to tie it all together, let’s consider the case of sending an email to a user a week before he will be charged for the extension of his subscription. So in our API implementation, when a user subscribes, we start the state machine with the user’s email and first name as additional info to pass to our lambda function that will actually send the email:
In this example the lambda function that will execute our business logic is called sendSubscriptionEmail
and the state machine’s name is futureEventStateMachine
. As the executionName
we choose the person’s email and the year for which he will pay the subscription, which should be unique (or you are making your customers pay twice!).
Now for our actual business logic, we send an email to our customer letting them know they will be charged next week:
That’s a wrap!
We created a generic, reusable future event scheduler using AWS Step Functions. Implemented using the Serverless Framework, we can use it to execute any type of business logic at a very precise moment in the future.
More material on the subject & inspiration
About Rik
Rik works as a Full Stack Engineer at NN, a financial services company active in 18 countries and the leading insurance company in the Netherlands. In the Catapult team, an in-house innovation team of NN, he focuses on new technology and developing applications to support the business in bringing innovations to life. Rik lives and loves to develop web and mobile apps as well as taking full stack to the next level with a focus on serverless and cloudnative applications.
Interested in working at NN? Check the NN careers website.