[Infographic] AWS SNS from a serverless perspective

The Simple Notification Service, or SNS for short, is one of the central services to build serverless architectures in the AWS cloud. SNS itself is a serverless messaging service that can distribute massive numbers of messages to different recipients. These include mobile end-user devices, like smartphones and tablets, but also other services inside the AWS ecosystem.

SNS’ ability to target AWS services makes it the perfect companion for AWS Lambda. If you need custom logic, go for Lambda; if you need to fan out messages to multiple other services in parallel, SNS is the place to be. 

But you can also use it for SMS or email delivery; it’s a versatile service with many possible use-cases in a modern serverless system.

aws sns

SNS pricing

SNS is a serverless service, which means it comes with pay-as-you-go billing. You pay about 50 cents per 1 million messages. If your messages are bigger than 64 KB, you have to pay for each additional 64 KB chunk as if it was a whole message.

AWS also offers the first 1 million requests each month for free; this includes 100000 deliveries via HTTP subscription.

SNS vs. SQS

SNS’ parallel delivery is different from SQS, the serverless queuing service of AWS. If you need to buffer events to remove pressure from a downstream service, then SQS is a better solution.

Another difference is SQS is pull-based, so you need a service actively grabbing an event from a queue, and AWS SNS is push-based so that it will call a service, like Lambda, that waits passively for an event.

SNS vs. EventBridge

EventBridge has similar use-cases as SNS but operates on a higher level. EventBridge can archive messages and target more services than SNS. SNS’ only targets are email addresses, phone numbers, HTTP endpoints, Lambda functions, and SQS queues. This means if you want to give your data to another AWS service, you need to put some glue logic in-between. At least a Lambda function, and it will cost extra money.

But SNS allows configuring a topic as FIFO, which guarantees precisely one message delivery. This lowers the throughput from about 9000 msgs/sec to about 3000 msgs/sec but can reduce the complexity of your Lambda code.

Don’t call Lambda from another Lambda

One rule when building serverless systems is “Don’t call a Lambda directly from another Lambda.” This rule comes from the fact that events from direct calls can get lost when one of the functions crashes, or it could lead to one function waiting until the other function finishes, which means double the costs.

This direct call rule means you always should put another service between your Lambda function calls. Sometimes these services follow from your use-cases, but when they don’t, and you’re about to make a direct call, you can grab SNS, EventBridge, or SQS to get around this issue.

Using SNS from Lambda

There are two ways SNS interacts with AWS Lambda: First, Lambda can send an event to an SNS topic, and second, a Lambda can subscribe to an SNS topic and receive events from it.

Sending Events from Lambda to an SNS Topic

To send a message to an SNS topic from your Lambda function, you need the SNS client from the AWS SDK and the ARN of your SNS topic.

Let’s look at an example Lambda that handles API Gateway events:

const { SNSClient, PublishCommand } = 
  require("@aws-sdk/client-sns")

const TargetArn = process.env.SNS_TOPIC_ARN

const client = new SNSClient()

exports.handler = async ({ body }) => {
  await client.send(new PublishCommand({
    Message: body,
    TargetArn
  }));
  return { statusCode: 200, body: "OK" }
};

The Lambda uses the AWS SDK v3, which is better modularized than the v2, which means more space for your custom code inside a Lambda. 

It’s a good practice to store the SNS topic ARN inside an environment variable, so you can change it without changing the code. Also, you should initialize the SNS client outside of the function handler, so it only happens on a cold-start.

You need to call the send method with a PublishCommand object to publish messages. The object requires a Message string, which we get from our API Gateway event body, and the TargetArn we got from an environment variable.

Receiving SNS Events with Lambda

To receive an SNS event with a Lambda, you need to subscribe your Lambda to an SNS topic. This way, the event that invokes the Lambda will be an SNS message.

Let’s look at how to set things up with the CDK:

import { Stack, StackProps } from "aws-cdk-lib"
import * as lambda from "@aws-cdk/aws-lambda"
import * as sns from "@aws-cdk/aws-sns"
import * as subscriptions from "@aws-cdk/aws-sns-subscriptions"

export class ExampleStack extends Stack {
  constructor(scope, id, props) {
    super(scope, id, props)

    const myTopic = new sns.Topic(this, "myTopic")

    const myFunction = new lambda.Function(this, "MyFunction", {
      runtime: lambda.Runtime.NODEJS_14_X,
      handler: "index.handler",
      code: lambda.Code.fromInline(`
        exports.handler = async ({ Records }) => {
          for (const record of Records) {
            const { Message } = record.Sns;
            console.log(Message);
          }
        }
      `),
    })

    const mySubscription = new subscriptions.LambdaSubscription(myFunction)

    myTopic.addSubscription(mySubscription)
  }
}

The first crucial part here is that you need to wrap the Lambda function into a subscription so that the CDK can link it up with an SNS topic.

The second part is that the event your Lambda function receives has its data inside a Records array, so you need to iterate it to get every record.

Piping API Gateway Events to SNS

Using AWS Lambda to glue things together is pretty straightforward but adds complexity and latency and costs extra money. That’s why you should do simple integrations directly between services like API Gateway and SNS.

Let’s look at another CDK example:

import { Stack } from "aws-cdk-lib"
import * as apiGateway from "@aws-cdk/aws-apigateway"
import * as sns from "@aws-cdk/aws-sns"
import * as integrations from "cdk-rest-api-integrations"

export class ExampleStack extends Stack {
  constructor(scope, id, props) {
    super(scope, id, props)

    const api = new apiGateway.RestApi(this, "emailApi")

    const emailsTopic = new sns.Topic(this, "emailsTopic")

    new integrations.SnsRestApiIntegration(this, "emailsIntegration", {
      topic: emailsTopic,
      restApiResource: api.root.addResource("emails"),
    })
  }
}

The example uses a third-party library that takes care of the event transformations. Usually, you would use the AwsServiceIntegration construct, which requires you to write VTL code that transforms the API Gateway event into something SNS understands. The library comes with some transformations out-of-the-box. 

If you send JSON via a POST request to the /emails resource of this REST API, API Gateway will directly pipe that data to the SNS topic; no Lambda needed!

Dashbird now supports SNS

Now that you learned that AWS SNS is a crucial part of many serverless systems, you should be happy to hear that with its latest update, Dashbird gives you insights into your SNS topics too!

dashbird sns monitoring

With its ability to run custom code, Lambda was low-hanging fruit for debugging; you could push all you wanted to know to a monitoring service. But all the other services on AWS are a bit trickier. 

Usually, you would learn about the issues inside other services when Lambda was calling them. But Lambda costs money, and some services, like API Gateway or EventBridge, are perfectly able to transform and distribute events directly to the services where they’re needed. No Lambda needed, and that’s how it should be! Only use Lambda if it simplifies something or if the direct integrations lack features.

With Dashbird’s new AWS SNS integration, you can now discover what is happening inside your architecture without the need to sprinkle Lambda functions all around the integration points. This saves you money, latency, and complexity!


Further reading:

AWS Kinesis vs SNS vs SQS (with Python examples)

Dashbird now integrates with 5 new AWS services

Triggering AWS Lambda with SNS

Read our blog

Why and How to Monitor AWS Elastic Load Balancing

Dashbird recently added support for ELB, so now you can keep track of your load balancers in one central place. It comes with all the information you expect from AWS monitoring services and more!

Monitor Your AWS AppSync GraphQL APIs with Simplicity

Dashbird has just added support for AppSync to help you monitor all of your AppSync endpoints without needing to browse dozens of logs or stumble through traces in the X-Ray UI.

AWS AppSync as a Gateway to Your Cloud Infrastructure

This article will discuss AppSync, AWS’s managed GraphQL service. Read on if you’re building a new backend or want to see if there is a more refined solution to the gateway problem than ELB and API Gateway.

Made by developers for developers

Dashbird was born out of our own need for an enhanced serverless debugging and monitoring tool, and we take pride in being developers.

What our customers say

Dashbird gives us a simple and easy to use tool to have peace of mind and know that all of our Serverless functions are running correctly. We are instantly aware now if there’s a problem. We love the fact that we have enough information in the Slack notification itself to take appropriate action immediately and know exactly where the issue occurred.

Thanks to Dashbird the time to discover the occurrence of an issue reduced from 2-4 hours to a matter of seconds or minutes. It also means that hundreds of dollars are saved every month.

Great onboarding: it takes just a couple of minutes to connect an AWS account to an organization in Dashbird. The UI is clean and gives a good overview of what is happening with the Lambdas and API Gateways in the account.

I mean, it is just extremely time-saving. It’s so efficient! I don’t think it’s an exaggeration or dramatic to say that Dashbird has been a lifesaver for us.

Dashbird provides an easier interface to monitor and debug problems with our Lambdas. Relevant logs are simple to find and view. Dashbird’s support has been good, and they take product suggestions with grace.

Great UI. Easy to navigate through CloudWatch logs. Simple setup.

Dashbird helped us refine the size of our Lambdas, resulting in significantly reduced costs. We have Dashbird alert us in seconds via email when any of our functions behaves abnormally. Their app immediately makes the cause and severity of errors obvious.