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.