简体   繁体   中英

publish a message to a sns topic from lambda

I have a lambda function that handles a POST request via AWS lambda function. It process the body of the post request and makes a query and returns a response.

MY LAMBDA FUNCTION

const { Pool, Client } = require("pg");
const userName = 'blah';
const hostEndPoint = 'blah';
const databaseType = 'blahblah';
const pwd = 'pass pass';
const portNumber = 5432;
var AWS = require('aws-sdk');

const pool = new Pool({
  user: userName,
  host: hostEndPoint,
  database: databaseType,
  password: pwd,
  port: portNumber
});


exports.handler = async (event) => {
  let body = JSON.parse(event.body);
  let name = body.name;
  let money = body.money;
  let todayDate = new Date();
  var status = 0;
  let text = 'INSERT INTO employee(name, date, salary) VALUES($1, $2, $3) RETURNING *';
  let values = [name, todayDate, money];
  var message = '';
  var status = 0;

  try {
    const res = await pool.query(text, values)
    message += 'successful'
    status = 200;
  } catch (err) {
    message += 'unsuccessful'
    if (err.code === '23505') {
      status = 406;
    }
  }

  var params = {
    Message: 'Hello From Lambda', /* required */
    TopicArn: 'arn:aws:sns:us-east-1:blahblahblah'
  };

  // Create promise and SNS service object
  var publishTextPromise = new AWS.SNS({ apiVersion: '2010-03-31' }).publish(params).promise();

  publishTextPromise.then(
    function (data) {
      console.log(`Message ${params.Message} send sent to the topic ${params.TopicArn}`);
      console.log("MessageID is " + data.MessageId);
    }).catch(
      function (err) {
        console.error(err, err.stack);
      });



  const response = {
    statusCode: status,
    body: JSON.stringify(message),
    headers: {
      "Access-Control-Allow-Origtin": '*'
    }
  };
  return response;
};

My Lambda Resource Policy Looks like this

{
  "Version": "2012-10-17",
  "Id": "default",
  "Statement": [
    {
      "Sid": "blah-blah-blah-blah",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:us-east-1:blah-blah-blah-blah-blah",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:execute-api:us-east-1:blahblahblahblha:blah/*/POST/"
        }
      }
    }
  ]
}

I have also created a SNS topic. I want to publish a message to the SNS topic if my status is 200. So before I return response. I want to do something like this.

if (status === 200){
  pubish some message to my sns topic
}

I am very new to aws and would love some guidance on how i can publish a message. I feel like i am close. I did come across this topic but it is confusing to me because i am editing code in lambda function so why would i need to require aws-sdk and also they are not talking about changing permission.

Updated code after trying below suggested answer

I assume your architecture looks something like this:

An API-Gateway accepts the request and invokes the lambda function you have shown us. That Lambda function the connects to a database and inserts a record. You now want this Lambda function to also publish to a SNS topic.

To achieve this, you need to do two things:

  1. Grant the Lambda function permissions on the SNS topic
  2. Write code to publish a message to the topic

Step 1 should come first and for this you need to edit the IAM Role that your function is using. The IAM Role specifies, which AWS services this lambda function is allowed to call. The Lambda Resource Policy you've shown us, grants the API Gateway the permissions to invoke/call your Lambda function - that has no influence on what the function can do.

If this is just for testing you can locate the IAM Role of the function inside Identity and Access Management and attach the AmazonSNSFullAccess policy - do not do this for any kind of production environment, this grants a lot more permissinons than necessary (In Production you'd add a custom policy that allows the action sns:Publish only on your topic).

Now your function has permissions to publish messages to your topic.

Step 2 means you need to edit your code. Importing the AWS SDK as described in the documentation you linked is necessary, because you want your code to interface with AWS services - for that you need the SDK. The other steps in that documentation seem reasonable except for setting the region, you don't need to do that if your topic lives in the same AWS region as your lambda function.

Some additional observations/suggestions:

  • You've got a typo in your CORS-Header Access-Control-Allow-Origtin - it should be Origin. You can also set this at the API Gateway, this way your function doesn't have to take care of it.
  • I recommend you get your database credentials from something like the AWS Secrets Manager or Systems Manager Parameter Store instead of storing them in the code
  • By setting up the connection pool outside of the handler you enable your code to re-use existing DB-Connections, well done!

You can see, return response; line will be run immediately when publish does not finish their task - publish a message to SNS. Because publish , publishTextPromise.then and return just are synchronization codes, it just take one tick (~0,00..1 second) to finish. When the return has been called for the handler function, the function will finish, this mean all doing task will be cancel (include publish process, the process need too many time (~ < 1s and > one tick to finish).

You mix async/await syntax with promise syntax (.then .catch), then process will not work as you think (or want), I recommend just use async/await syntax if you can.

With your code, I guest the publish task will not effect to response, it just try to publish a message to SNS. My suggestion, change

  publishTextPromise.then(
    function (data) {
      console.log(`Message ${params.Message} send sent to the topic ${params.TopicArn}`);
      console.log("MessageID is " + data.MessageId);
    }).catch(
      function (err) {
        console.error(err, err.stack);
      });

to

  await publishTextPromise // wait until the task done
    .then((data) => {
      console.log(`Message ${params.Message} send sent to the topic ${params.TopicArn}`);
      console.log("MessageID is " + data.MessageId);
    })
    .catch((err) => {
      console.error(err, err.stack);
    });

await keyword has been added, and I prefer arrow function syntax

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM