Skip to main content

SNS Trigger Lambda

Amazon Simple Notification Service (Amazon SNS) is a web service that makes it easy to set up, operate, and send notifications from the cloud.

Description

sns-lambda-log-01.png

We’ll show how you can invoke an AWS Lambda through an SNS subscription using LocalStack. When Amazon SNS invokes a Lambda function asynchronously, Lambda returns a 202 HTTP status code back to Amazon SNS. The status code shows that Lambda has accepted the message for later processing. For more information, see Asynchronous invocation.

Prerequisites

Run LocalStack

version: '3.8'

services:
localstack:
image: localstack/localstack
container_name: localstack_main
ports:
- "4566-4599:4566-4599"
environment:
- SERVICES=sns,s3,sqs,dynamodb,ses,lambda,logs,stepfunctions
- DYNAMODB_SHARE_DB=1
- DEBUG=1
- DATA_DIR=/tmp/localstack/data
- DOCKER_HOST=unix:///var/run/docker.sock
volumes:
- "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"

Create Lambda

Source Code: https://github.com/ZbCiok/zjc-examples/tree/main/aws/aws/lambda/sns-trigger-lambda

  • Project Structure

.
├── pom.xml
└── src
├── main
│   ├── java
│   │   └── com
│   │   └── example
│   │   ├── Main.java
│   │   └── SnsRequestHandler.java
│   └── resources
└── test
└── java
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>sns-trigger-lambda</artifactId>
<version>0.0.1</version>

<properties>
<encoding>UTF-8</encoding>
<project.build.sourceEncoding>${encoding}</project.build.sourceEncoding>
<project.reporting.outputEncoding>${encoding}</project.reporting.outputEncoding>
<java.version>21</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-events</artifactId>
<version>3.11.4</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>
  • SnsRequestHandler.java

package com.example;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.SNSEvent;

import java.util.List;
import com.amazonaws.services.lambda.runtime.events.SNSEvent.SNSRecord;
import lombok.extern.java.Log;

import java.util.Iterator;

@Log
public class SnsRequestHandler implements RequestHandler<SNSEvent, Boolean> {
LambdaLogger logger;

@Override
public Boolean handleRequest(SNSEvent event, Context context) {
log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
logger = context.getLogger();
List<SNSRecord> records = event.getRecords();
if (!records.isEmpty()) {
Iterator<SNSRecord> recordsIter = records.iterator();
while (recordsIter.hasNext()) {
processRecord(recordsIter.next());
}
}
return Boolean.TRUE;
}

public void processRecord(SNSRecord record) {
try {
String message = record.getSNS().getMessage();
logger.log("message: " + message);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
  • Deploy Lambda Function

    • mvn clean package

    • Create Function
    awslocal lambda create-function \
    --region us-east-1 \
    --function-name localstack-lambda-sns \
    --runtime java21 \
    --zip-file fileb://sns-trigger-lambda-0.0.1.jar \
    --handler com.example.SnsRequestHandler \
    --role arn:aws:iam::000000000000:role/example-lambda-noop-role \
    --timeout 120
    • zip-file fileb://localstack-lambda-sns-0.0.1.jar - generated by mvn clean package

SNS Create a topic

awslocal sns create-topic --name example-topic --region us-east-1
awslocal sns list-topics
{
"Topics": [
{
"TopicArn": "arn:aws:sns:us-east-1:000000000000:example-topic"
}
]
}

Creating a subscription

Let’s create a subscription on the example-topic. This will trigger the Lambda when we publish an event to the topic.

awslocal sns subscribe \
--region us-east-1 \
--protocol lambda \
--topic-arn arn:aws:sns:us-east-1:000000000000:example-topic \
--notification-endpoint arn:aws:lambda:us-east-1:000000000000:function:localstack-lambda-sns
awslocal sns list-subscriptions
{
"Subscriptions": [
{
"SubscriptionArn": "arn:aws:sns:us-east-1:000000000000:example-topic:ae242544-2b1a-4ba8-a324-a024b73bc1cf",
"Owner": "000000000000",
"Protocol": "lambda",
"Endpoint": "arn:aws:lambda:us-east-1:000000000000:function:localstack-lambda-sns",
"TopicArn": "arn:aws:sns:us-east-1:000000000000:example-topic"
}
]
}

Publish a SNS event & Invoke the Lambda

Publish an event to the topic:

awslocal sns publish \
--region us-east-1 \
--topic-arn arn:aws:sns:us-east-1:000000000000:example-topic \
--message "Hello Lambda..........!"

Verify if the Lambda was invoked

Docker Log:


...
localstack_main | 2024-09-26T07:24:51.088 DEBUG --- [ns:$LATEST_0] l.s.l.i.version_manager : [localstack-lambda-sns-43f017bb-ee5d-49c4-a5b6-922da7d48ee5] Sep 26, 2024 7:24:51 AM com.example.SnsRequestHandler handleRequest
localstack_main | 2024-09-26T07:24:51.088 DEBUG --- [ns:$LATEST_0] l.s.l.i.version_manager : [localstack-lambda-sns-43f017bb-ee5d-49c4-a5b6-922da7d48ee5] INFO: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
localstack_main | 2024-09-26T07:24:51.088 DEBUG --- [ns:$LATEST_0] l.s.l.i.version_manager : [localstack-lambda-sns-43f017bb-ee5d-49c4-a5b6-922da7d48ee5] message: Hello Lambda..........!END RequestId: 43f017bb-ee5d-49c4-a5b6-922da7d48ee5
...

Notice:

INFO: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
message: Hello Lambda..........!

localstack-main | 2024-09-20T10:38:43.258 INFO --- [et.reactor-1] localstack.request.http /
: POST /_localstack_lambda/537e999fe486e7d46879e3fafcf1dc73/invocations/bb479d30-62d8-40b9-8798-5f393c2a9644/response => 202

response => 202
For asynchronous invocation, Lambda places the event in a queue and returns a success response without additional information. A separate process reads events from the queue and sends them to your function.