4

I've written an AWS lambda function to send a text message when an S3 object is uploaded. I've confirmed the subscription and I can receive test messages sent from the SNS console.

When I test the lambda all the logs say the method succeeds but no sons message ever arrives. Here is the function (mostly just the sample template but changed my topic arn in this post for security). Any hints of things to test/try next are appreciated.

console.log('Loading function');
var aws = require('aws-sdk');
var s3 = new aws.S3({ apiVersion: '2006-03-01' });
exports.handler = function(event, context) {
    var bucket = event.Records[0].s3.bucket.name;
    var key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
    var params = {
        Bucket: bucket,
        Key: key
    };
    var sns = new aws.SNS();
    console.log('start of brians sns function')
    var pubResult = sns.publish({
        Message: 'Test publish to SNS from Lambda',
        TopicArn: 'arn:aws:sns:us-east-1:xxxxxxxxxxxx:lambdatop'
    }, function(err, data) {
        if (err) {
            console.log(err.stack);
            return;
        }
        console.log('push sent');
        console.log(data);
    });
    console.log('after sns publish:')
    console.log(pubResult)
    context.done(null, 'Brians Function Finished!');  
};
danronmoon
  • 3,814
  • 5
  • 34
  • 56
Brian Tarbox
  • 2,335
  • 1
  • 20
  • 30

2 Answers2

10

You are calling context.done() right after calling publish(). The publish() function is an asynchronous call, and you aren't waiting for it to finish. Also, I don't think your variable pubResult contains what you expect it to.

Try this:

console.log('Loading function');
var aws = require('aws-sdk');
exports.handler = function(event, context) {
    var sns = new aws.SNS();
    console.log('start of brians sns function')
    sns.publish({
        Message: 'Test publish to SNS from Lambda',
        TopicArn: 'arn:aws:sns:us-east-1:xxxxxxxxxxxx:lambdatop'
    }, function(err, data) {
        if (err) {
            console.log(err.stack);

            // Notify Lambda that we are finished, but with errors
            context.done(err, 'Brians Function Finished with Errors!');  
            return;
        }
        console.log('push sent');
        console.log(data);

        // Notify Lambda that we are finished
        context.done(null, 'Brians Function Finished!');  
    });
};
Mark B
  • 183,023
  • 24
  • 297
  • 295
  • 1
    Thank you...I now get: errorMessage": "Process exited before completing request. Do you know how to wait for the publish to finish before exiting? – Brian Tarbox Dec 10 '15 at 16:05
  • Are you running the exact code from my answer, and getting that error message? Are there any errors in the console log? If you copy/paste my answer exactly, and update the TopicArn, it should call the SNS publish function and only exit after the publish callback is called. – Mark B Dec 10 '15 at 16:07
  • That worked enough for me to see that I was actually having a security policy error. Fixed that and it worked like a champ. Thanks! – Brian Tarbox Dec 10 '15 at 16:39
  • @MarkB, Any idea if we can get this TopicARN dynamically in above code. Here is my question, https://stackoverflow.com/questions/44937508/aws-cloudformation-for-lambda-and-sns-topic# – User0911 Jul 05 '17 at 23:54
2

One more way to tackle this issue is wrap the SNS Publish in a Promise and wait for it to be resolved from the Lambda handler.

exports.handler = async (event) => {
    await publishSNS(record, process.env.TOPIC_ARN);
}

async function publishSNS(payload, topicArn) {
    await SNS.publish({
        Message: JSON.stringify(payload),
        TargetArn: topicArn
    }).promise().then((data) => {
        console.log('SNS push succeeded: ', data);
    }).catch((err) => {
        console.error(err);
    });
}
HariJustForFun
  • 521
  • 2
  • 8
  • 17