0

I've got a problem I cannot solve myself. My lambda function works as expected when invoked locally, but it does not send the text message when called from AWS Lambda. It doesn't log any error either.

Here's my code, I've only starred the private stuff out:

import request from 'request';
import AWS from "aws-sdk";

const options = {***};
const sentAlert = async msg => {
  const sns = new AWS.SNS();
  await sns.publish({
    Message: msg,
    PhoneNumber: '***',
    MessageAttributes: {
      'AWS.SNS.SMS.SenderID': {
        'DataType': 'String',
        'StringValue': '***'   
      }
    }
  }, function (err, data) {
  if (err) {
    console.log(err.stack);
    return;
  }
  });
  console.log('sms sent');
};

export const getAlert = async (event, context, callback) => {
  request(options, (err, res, body) => {
    if (err) { return console.log('error: ', err); }
    if (body.length === 0 ) { return }
    console.log(`***`);
    const optionsId = {*** };
    request(optionsId, (err, res, body) => { 
      const msg = body.current.indexes[0].description;
      console.log('msg: ', msg);
      sentAlert(msg);
    });
  });
};

I test it locally using serverless invoke local --function getSmogAlert and it works just as expected, I get the sms from AWS, but when I call it with serverless invoke --function getSmogAlert - it returns null and doesn't send any text message. I've had similar problems with Nexmo and thought that maybe AWS.SNS will help me, but nope.

Any help, please?

chris
  • 15
  • 7
  • Please check the AWS CloudWatch Logs for the Lambda function and include any log output from the function invocation. – Mark B Oct 23 '18 at 18:02
  • It's only stuff like `START RequestId: 824ea951-d6e8-11e8-a428-77d70245b74d Version: $LATEST END RequestId: 824ea951-d6e8-11e8-a428-77d70245b74d REPORT RequestId: 824ea951-d6e8-11e8-a428-77d70245b74d Duration: 8.84 ms Billed Duration: 100 ms Memory Size: 1856 MB Max Memory Used: 45 MB ` – chris Oct 23 '18 at 18:05
  • Check IAM permissions, does your Lambda role has `sns:publish`? – yorodm Oct 23 '18 at 19:36
  • In your `sns.publish` call I miss the parameter `TopicArn`. But according the log, the execution gets not so far. In your handler `getAlert` I miss a `callback(...)` call, so the lambda executor probably ignore the promise made by the `request(...)` call and ends before the execution comes to the SNS publishing... – ttulka Oct 24 '18 at 06:39

1 Answers1

0

As I wrote in my comment, I think you confuse the promises and callbacks in the execution. Try this changes:

const options = {***};
const sentAlert = (msg, callback) => {
  const sns = new AWS.SNS();
  await sns.publish({
    TopicArn: ***
    Message: msg,
    PhoneNumber: '***',
    MessageAttributes: {
      'AWS.SNS.SMS.SenderID': {
        'DataType': 'String',
        'StringValue': '***'   
      }
    }
  }, function (err, data) {
  if (err) {
    console.log(err.stack);
    callback(err);
  }
  });
  console.log('sms sent');
  callback(null)
};

export const getAlert = (event, context, callback) => {
  request(options, (err, res, body) => {
    if (err) { 
      console.log('error: ', err);
      callback(err); 
    }
    if (body.length === 0 ) {
      console.log('Got no body!') 
      callback(null) 
    }
    console.log(`***`);
    const optionsId = {*** };
    request(optionsId, (err, res, body) => {
      if (err) {
        console.log(err.stack);
        callback(err);
      } 
      const msg = body.current.indexes[0].description;
      console.log('msg: ', msg);
      sentAlert(msg, callback);
    });
  });
};

But in general, I would prefer to use async/await mechanism supported by AWS Lambda nodejs8.10 image. That would make your code simple and easier to reason about.

ttulka
  • 10,309
  • 7
  • 41
  • 52
  • I've added permission to use sns, made the proposed changes, and also remove the await from `SentAlert` - and still the same, it works when invoked locally, and not from lambda... – chris Oct 24 '18 at 13:37
  • Try to trace the execution via Cloud9 or just with logs - see where the execution stops. – ttulka Oct 24 '18 at 13:57
  • One more thing I overlooked: try to remove `async` from the handler function. I will edit my answer so. – ttulka Oct 24 '18 at 14:00
  • Ok, I've got something: a useful log in CloudWatch: `User: arn:aws:sts::***:assumed-role/sns/***Alert is not authorized to perform: SNS:Publish on resource: PHONE_NUMBER`. – chris Oct 24 '18 at 14:59
  • It means your lambda role has no permission to perform "sns:publish" – ttulka Oct 24 '18 at 15:25
  • Adding full sns access role solved the problem, thanks guys! – chris Oct 24 '18 at 21:06
  • @chris Then you can accept the answer. Still I think you should consider async/await style instead of callbacks. See https://medium.com/@ThatGuyTinus/callbacks-vs-promises-vs-async-await-f65ed7c2b9b4 – ttulka Oct 25 '18 at 06:40