I have an Amazon Lambda instance and an Amazon SNS instance. The Lambda code watches for changes in our database and I would like it to make a call to Amazon SNS to send pushes to our users. For example:
When a user on one of our forums gets a new message, the Lambda code recognizes this change every time it is run (every 10 minutes) and should send a push to the user's smartphone via SNS.
I'm running into a wall when it comes to the documentation; Amazon's docs only talk about how to trigger Lambda code via SNS, but not the reverse. Does anyone have an example of how I can accomplish this?
There is nothing special about pushing SNS notifications in the context of Lambda. I would think of it as just another external service that you interact with.
What you could do is pull in the AWS SDK in your lambda code and after that use the code to make the SNS calls. You will need to inject the right credentials to be able to call the Amazon SNS API (but you probably do something similar for getting the database endpoint and credentials if you are talking to the database)
Yes, you can use AWS Lambda to achieve what you want. You also need to give proper IAM Permissions allowing your Lambda IAM Role to publish messages to you SNS Topic.
Example SNS Publish IAM Policy:
{
"Statement":[ {
"Effect":"Allow",
"Action":"sns:Publish",
"Resource":"arn:aws:sns:*:<your account id>:<your topic id>"
} ]
}
You can use the lambda below to push an SNS message to a user, but you must know what the endpoint ARN is for that user. For example, if in an Android app, when the user logs in you will have the app send a GCM (Google Cloud Messaging) token to your backend (via an API call that triggers a lambda, for example). Your backend, which is connected to GCM, can then use this token to lookup which endpoint ARN corresponds to such user and put that in the lambda below. Alternatively, you can have the app send the endpoint ARN directly to your backend, though I think it might be a bit less secure. Make sure you give IAM permissions to publish to your app via SNS. You can use the lambda below to push the message:
var AWS = require('aws-sdk');
var sns = new AWS.SNS({apiVersion: '2010-03-31'});
exports.handler = (event, context, callback) => {
console.log(JSON.stringify(event))
var payload = {
"default": "The message string.",
"GCM":"{"+
"\"notification\":{"+
"\"body\":\"PUT NOTIFICATION BODY HERE\","+
"\"title\":\"PUT NOTIFICATION TITLE HERE\""+
"}"+
"}"
};
payload = JSON.stringify(payload);
var params = {
TargetArn: 'PUT THE ENDPOINT ARN HERE',
Subject: 'foo2',
MessageStructure: 'json',
Message: payload
}
sns.publish(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
};
Related
I want to use a SNS subscription to trigger a Lambda function.
First I have created a topic and subscription via the AWS SDK:
import {SubscribeCommand } from "#aws-sdk/client-sns";
import {snsClient } from "./libs/snsClient.js";
// Set the parameters
const params = {
Protocol: "lambda" /* required */,
TopicArn: "TOPIC_ARN", //TOPIC_ARN
Endpoint: "LAMBDA_FUNCTION_ARN", //LAMBDA_FUNCTION_ARN
};
const run = async () => {
try {
const data = await snsClient.send(new SubscribeCommand(params));
console.log("Success.", data);
return data; // For unit tests.
} catch (err) {
console.log("Error", err.stack);
}
};
run();
It is creating the subscription, but when I check the Lambda, this sub is not appearing as a Lambda trigger.
When I create the subscription manually without using the SDK it's working.
I would like to know why my subscription that created with the SDK is not showing in the Lambda's trigger.
Looks like you are missing the IAM permissions. SNS needs explicit permission to invoke your Lambda.
See How do I subscribe a Lambda function to an Amazon SNS topic in the same account? in the docs. The lambda add-permission CLI step from the example is the same as the AddPermissionCommand in the SDK Lambda client. Provide your SNS topic's ARN.
I am trying to register Chime meeting event to a SNS topic, but I am not getting any message on the topic subscription. I am not very familiar with SNS and I am not sure how to debug.
I am using nodejs library (aws-sdk#^2.656.0) to create the meeting with the following configuration:
{
"ExternalMeetingId":"meeting1587397186860",
"ClientRequestToken":"<TOKEN>,
"MediaRegion":"eu-central-1",
"NotificationsConfiguration": {
"SnsTopicArn":"arn:aws:sns:eu-central-1:<ID>:<topic>"
}
}
import { Chime, Endpoint } from 'aws-sdk';
const chime = new Chime({ region: 'us-east-1', accessKeyId: accessKey, secretAccessKey: secretKey });
chime.endpoint = new Endpoint('https://service.chime.aws.amazon.com/console');
chime.createMeeting(meetingConfiguration).promise().then(()=>{
...
});
...
The meeting is created without any error, but I do not get any notification on the SNS topic for any event. I also tried to set the topic as public and tried to publish message to it from AWS cli, and it worked.
The answer is: it currently only works if your SNS/SQS/Eventbrige is on us-east-1. Not documented anywhere...
I have created an AWS IoT rule. It triggers a Lambda function when client sends a message to the terminal1/ topic (Client is sending messages to the terminal1/ using certificate files generated from AWS IoT.). I need a Lambda function to generate a new message using the client message and send to another topic (terminal2/test).
I have tried triggering "Republish messages to an AWS IoT topic". However, it sends data to a particular topic. It just forwards the same message (I need to send a different message).
I have created a Lambda function to send a message to another topic. But I could not authenticate the endpoint.
Here is the Lambda Function I have created (According to this),
'use strict';
// Load the AWS SDK
var AWS = require("aws-sdk");
exports.handler = (event, context, callback) => {
var iotdata = new AWS.IotData({
endpoint: 'akugdx70brb.iot.us-west-2.amazonaws.com:8883',
apiVersion: '2015-05-28'
});
var params = {
topic: 'terminal2/test/',
payload: new Buffer('...') || 'STRING_VALUE',
qos:1
};
iotdata.publish(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
};
It generates this error,
2018-05-01T06:22:02.394Z f5a570ef-4d07-11e8-b8a2-6bad8f2982f7 { Error: write EPROTO 139935652661056:error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate:../deps/openssl/openssl/ssl/s3_pkt.c:1493:SSL alert number 42
139935652661056:error:1409E0E5:SSL routines:ssl3_write_bytes:ssl handshake failure:../deps/openssl/openssl/ssl/s3_pkt.c:659:
at exports._errnoException (util.js:1018:11)
at WriteWrap.afterWrite (net.js:800:14)
message: 'write EPROTO 139935652661056:error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate:../deps/openssl/openssl/ssl/s3_pkt.c:1493:SSL alert number 42\n139935652661056:error:1409E0E5:SSL routines:ssl3_write_bytes:ssl handshake failure:../deps/openssl/openssl/ssl/s3_pkt.c:659:\n',
code: 'NetworkingError',
errno: 'EPROTO',
syscall: 'write',
region: 'us-west-2',
hostname: 'akugdx70brb.iot.us-west-2.amazonaws.com',
retryable: true,
time: 2018-05-01T06:22:02.394Z } 'Error: write EPROTO 139935652661056:error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate:../deps/openssl/openssl/ssl/s3_pkt.c:1493:SSL alert number 42\n139935652661056:error:1409E0E5:SSL routines:ssl3_write_bytes:ssl handshake failure:../deps/openssl/openssl/ssl/s3_pkt.c:659:\n\n at exports._errnoException (util.js:1018:11)\n at WriteWrap.afterWrite (net.js:800:14)'
I guess that it means I could not authenticate the host, I have not used any certificates when creating the Lambda Function. How can I send an MQTT message to the same host, but to a different topic using AWS Lambda? (The above Lambda Function triggers when a client sends a message, Do I have to re-authenticate the server to send a message to a different topic?)
try using
AWS.config.update({
accessKeyId: <accessKeyId>,
secretAccessKey: <secretAccessKey>,
region: <region>
});
Depending on what you want to generate, you may be able to transform the input message using the topic rule itself, and skip being charged for the lambda invocation. See https://docs.aws.amazon.com/iot/latest/developerguide/iot-substitution-templates.html for an example.
Your lambda should use a role which has access to IoT policy. Your lambda execution role doesnt have enough privileges to write or connect and publish to IoT.
I am writing a Push Notification service with AWS. A User can have multiple devices registered for receiving notifications.
I store each ARN (Amazon Resource Name) in DynamoDB. When a notification is being sent to a User, I obtain all ARNs and publish a notification to each.
However, at some point, an ARN can become disabled. That of course means that a notification cannot be sent to this specific device.
How can I use the aws-sdk to determine whether an Endpoint is enabled/disabled before attempting to send a notification?
Right now, I get a HTTP 502 Internal Server Error response.
CloudWatch logs:
018-02-21T16:31:03.742Z 9bc412f6-1724-11e8-aa7b-596b69243ced {
EndpointDisabled: Endpoint is disabled .
...
message: 'Endpoint is disabled',
code: 'EndpointDisabled',
time: 2018-02-21T16:31:03.742Z,
requestId: '6217ac24-89f4-5be5-b6da-ff2328f3cdf4',
statusCode: 400,
retryable: false,
retryDelay: 24.93677139755519 }
My service stack:
API Gateway
AWS Lambda
DynamoDB
AWS SNS
As previously mentioned, I am using aws-sdk.
You can use AWS.SNS.getEndpointAttributes():
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SNS.html#getEndpointAttributes-property
var params = {
EndpointArn: 'STRING_VALUE' /* required */
};
sns.getEndpointAttributes(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
This returns several attributes including the Enabled flag:
Enabled -- flag that enables/disables delivery to the endpoint. Amazon SNS
will set this to false when a notification service indicates to Amazon SNS
that the endpoint is invalid. Users can set it back to true, typically after
updating Token.
I am using AWS to chain lambdas together by having a second lambda subscribe to the SNS feed of the first lambda. The second lambda was not receiving anything from the first lambda and I also get no notification in CloudWatch (or my personal email that I subscribed with) that the SNS event has been triggered. So, I am wondering the question: How do I make sure my SNS receives an event from my lambda firing?
When I use the SNS web UI I get logs like these and my lambda logs show they have been touched, but only when I manually send a message.
{
"notification": {
"messageMD5Sum": "e9a72884afc5d9568f2748e34a4e50a4",
"messageId": "04f4a199-cd25-5a45-a877-f054df9b2adf",
"topicArn": "arn:aws:sns:us-east-1:xxxxxxxxxxxx:first-lambda",
"timestamp": "2017-06-28 02:12:14.098"
},
"delivery": {
"deliveryId": "173dca7a-7b31-55a2-8ee9-9bb7698f35f6",
"destination": "arn:aws:lambda:us-east-1:xxxxxxxxxx:function:second-labmda",
"providerResponse": "{\"lambdaRequestId\":\"33972992-5ba7-11e7-b363-09e0f6dc8594\"}",
"dwellTimeMs": 134,
"attempts": 1,
"statusCode": 202
},
"status": "SUCCESS"
}
I've given my lambda publish permissions in it's role, but that only shows up in IAM and when I view its policy inside of the lambda itself on the GUI I just see lambda firing permissions for the lambda itself. I also am sure that my SNS has permissions to write to the lambda because when you set up the lambda (as I did more than once yesterday) it asks for you to grant privileges to the SNS topic. However, even when testing the SNS topic the lambda is never reached, but I do get an email if I subscribe with my email account.
tl;dr
First lambda should be triggering an SNS event that a second lambda subscribes to. The SNS event is not receiving any data from my first lambda except for two logs in the middle of the night that never went through to my second lambda. How do I make sure my SNS receives an event from my lambda firing?
Solved this by adding a service to my lambda to send the message.
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.sns.AmazonSNSClient;
import com.amazonaws.services.sns.model.PublishRequest;
public class SNSPublishService {
private static final String ACCESS_KEY = "credential1";
private static final String SECRET_KEY = "credential2";
private static final String ARN = "arn:aws:sns:<region>:<id>:<topicname>";
public static void publish(String body) throws InterruptedException {
AmazonSNSClient service = new AmazonSNSClient(new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY));
PublishRequest publishRequest = new PublishRequest()
.withTargetArn(ARN)
.withMessage(body);
service.publish(publishRequest);
}}