visit
Note: All the if you want to check out the end result right away.
The init
function is the only exposed function, which is hooked up to . It takes a single number
parameter which it validates, upon success, it publishes an SNS topic and sends along the number
value.
The SNS topic will trigger a second function called calculate
. This function will perform the calculation and log out the result to the console. This mimics a heavy computational background task such as data processing, image manipulation or machine learning calculations.
If the calculate
function fails, the Dead Letter Queue SNS topic will receive a message and trigger the error
function.
Every function invoked asynchronously will twice retry its execution upon failure. Using the Dead Letter Queue as a pool for your error logs is a smart use-case.
Now you’re wondering, why all the complication with SNS instead of just invoking the second lambda function from the first one with ? First of all, it’s a huge anti-pattern for asynchronous workflows, which is our case. Otherwise, it’s fine if you need the response from the second lambda function right away. Another issue is hitting Lambda’s concurrency limits pretty fast. It can result in losing invocations and dropping data. Sending your data through a pub/sub service like SNS or a queue like will make sure you have data integrity. Makes sense now? Sweet, let’s talk a bit more about SNS.Amazon Simple Notification Service (SNS) is a flexible, fully managed and mobile notifications service for coordinating the delivery of messages to subscribing endpoints and clients.
- AWS Docs
In English, this means it’s a way of sending notifications between services on a publisher/subscriber basis. One service publishes some data about a topic and sends it along its way. SNS will then funnel it to all the subscribers of that particular topic. Key focus is on topic here, you’ll see why a bit further down.
$ npm i -g serverless
Note: If you’re using Linux, you may need to run the command as sudo.
Once installed globally on your machine, the commands will be available to you from wherever in the terminal. But for it to communicate with your AWS account you need to configure an IAM User. Jump over , then come back and run the command below, with the provided keys.$ serverless config credentials \ --provider aws \ --key xxxxxxxxxxxxxx \ --secret xxxxxxxxxxxxxx
Now your Serverless installation knows what account to connect to when you run any terminal command. Let’s jump in and see it in action.
What’s a service? It’s like a project. It’s where you define AWS Lambda functions, the events that trigger them and any AWS infrastructure resources they require, including SNS which we’ll add today, all in a file called serverless.yml.
Back in your terminal type:$ serverless create \ --template aws-nodejs \ --path lambda-sns-dlq-error-handling
The create command will create a new service. What a surprise! We also pick a runtime for the function. This is called the template. Passing in aws-nodejs
will set the runtime to Node.js. Just what we want. The path will create a folder for the service.
Open up the lambda-sns-dlq-error-handling folder with your favorite code editor. There should be three files in there, but for now, we’ll only focus on the serverless.yml. It contains all the configuration settings for this service. Here you specify both general configuration settings and per function settings. Your serverless.yml will be full of boilerplate code and comments. Feel free to delete it all and paste this in.
Let’s break down what’s going one here. Check out the functions
section. There are three functions here. From top to bottom they're init
, calculate
, and error
. The init
function will get triggered by a simple HTTP request, which we invoke through API Gateway. Familiar territory for us.
However, the calculate
and error
functions are triggered by SNS topics. Meaning we will have logic in the init
function that will publish messages to a topic named calculate-topic
while the calculate
function is subscribed to the same topic.
Moving on, the error
function is subscribed to the dlq-topic
while the calculate
function will publish messages to this topic if it fails, as you can see with the onError
property. Now stuff makes sense, right?
What else, take a look at the iamRoleStatements
, they specify that our functions have permission to trigger, and get invoked by SNS topics. While the serverless-pseudo-parameters
plugin lets us reference our AccountId
and Region
with the CloudFormation syntax, making it much easier to keep our SNS ARNs consistent across all resources.
Luckily, this part will be short. Just one package to install. First, initialize npm and then you can install serverless-pseudo-parameters
.
$ npm init -y && npm i serverless-pseudo-parameters
That’ll do.
Let’s keep all three functions in separate files, to keep it simple. First of all create an init.js file and paste this snippet in.
We have a few helper functions and the exported lambda function at the bottom. What’s going on here? The lambda validates input and publishes some data to the calculate-topic
SNS topic. That's everything this function is doing. The calculate-topic
SNS topic will trigger the calculate
lambda function. Let's add that now.
Create a file and name it calculate.js. Paste this snippet in.
As you see this is just a simple factorial calculation implemented with a recursive function. It’ll calculate the factorial of the number we published to the SNS topic from the init
function.
An important note here is that if the calculate
function fails a total of three times, it'll publish messages to the Dead Letter Queue SNS topic we specified with the onError
property in the serverless.yml file. The Dead Letter Queue will then trigger the error
function. Let's create it now so it can log out errors to CloudWatch. Create an error.js file, and paste these lines in.
For now, this will do. However, ideally, you would have structured logging with detailed info about everything going on. That’s a topic for another article.
$ serverless deploy
You can see the endpoint get logged to the console. That’s where you will be sending your requests.
$ curl -H "Content-Type: application/json" \ -d '{"number":1000}' \ //<id>.execute-api.eu-central-1.amazonaws.com/dev/init
If everything works like it should, the result of the calculation will be logged to CloudWatch. If not, well then you’re out of luck. In cases like these, I default to using to debug what’s going on. It’s to set up.
After hitting the endpoint a few times with a couple of different values here’s the result. The init
function works as expected.
But, what really interests us is the calculate
function. Here's what that looks like when it's successful.
When it fails it’ll specify a crash and show the error logs.
After two retries it’ll send a message to the Dead Letter Queue and trigger the error
function.
Sweet! We’ve tested all the different scenarios. Hope this clears things up a bit.
Again, here’s the , if you want to take a look at the code. It can act as a starter for your own use-cases where you need SNS messages triggering lambda functions. Give it a star if you like it and want more people to see it on GitHub. If you want to read some of my previous serverless musings head over to or Or, take a look at a few of my articles right away:
Hope you guys and girls enjoyed reading this as much as I enjoyed writing it. If you liked it, slap that tiny clap so more people here on Medium will see this tutorial. Until next time, be curious and have fun.
Originally published at .