等待AWS SNS发布回调以将值返回给调用方法

时间:2017-12-14 05:13:34

标签: javascript node.js async-await amazon-sns aws-sdk-js

我正在尝试在用户请求重置密码时发送短信。我想等待发送消息以提醒用户是否成功。我目前正在尝试如下:

async function sendResetPasswordTextMessage(req, res) {
    let result = {};

    let phoneNumber = req.body.phoneNumber;                

    if (phoneNumber === undefined) {                       
        return sendInvalidParametersMessage(res);          
    }                                                      

    phoneNumber = phoneNumber.toString();                  

    const userProfile = await models.UserProfile.findOne({ 
        where: {                                           
            phoneNumber: phoneNumber                       
        }                                                  
    });                                                    
    ************************** RELEVANT CODE TO ISSUE *************************
    if (userProfile) {
        const message = "Your username is:\n" + userProfile.username;
        const sent = await AWSSNSClient.sendMessage(message, phoneNumber);

        if (!sent) {
            result.error = setTitleAndMessage("Error", "An error occurred");
        } else {
            result.success = setTitleAndMessage("Success", "Message sent"); 
        }
    }
    return res.send(result);
    ***************************************************************************
}

在我的其他类AWSSNSClient中,我有以下sendMessage函数:

function sendMessage(message, phoneNumber) {
    const params = { 
        Message: message, 
        MessageStructure: "string", 
        PhoneNumber: "+1" + phoneNumber
    };
    let sent = false;
    sns.publish(params, function(err, data) {
        if (err) {
            console.log(err, err.stack); // an error occurred
        }
        else {
            sent = true;
        }
    });

    return sent;
}

我无法弄清楚如何使sendMessage等待sns.publish在返回之前返回。我试过把它变成异步方法并在sns.publish上添加await,但是在send发送设置为true之前函数仍会返回。

我知道邮件发送没有错误,因为我收到它们并且没有打印控制台日志。

6 个答案:

答案 0 :(得分:9)

今天在Google上偶然发现了这个问题,试图自己解决-我现在正在使用的简短答案:

  

您现在可以使用Async / Await进行此操作—并使用扩展名.promise()调用AWS服务(例如SNS),以告诉aws-sdk使用该服务功能(SNS)的承诺版本。基于回调的版本。

这里唯一需要说明的是,包含函数必须还必须异步才能使用await语法。

例如:

let snsResult = await sns.publish({
    Message: snsPayload,
    MessageStructure: 'json',
    TargetArn: endPointArn
}, async function (err, data) {
    if (err) {
        console.log("SNS Push Failed:");
        console.log(err.stack);
        return;
    }
    console.log('SNS push suceeded: ' + data);
    return data;
}).promise();
  

重要的是最后的.promise()。有关以异步/基于承诺的方式使用aws-sdk的完整文档,请参见:https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/using-promises.html

要运行另一个aws-sdk任务,您可以类似地向该函数添加await和.promise()扩展名(假设可用)。

对于遇到此线程并实际上只是想将多个aws-sdk承诺推送到一个数组并等待该完整数组完成(不考虑哪个承诺首先执行)的任何人,我都会得到以下结果:

let snsPromises = [] // declare array to hold promises
let snsResult = await sns.publish({
    Message: snsPayload,
    MessageStructure: 'json',
    TargetArn: endPointArn
}, async function (err, data) {
    if (err) {
        console.log("Search Push Failed:");
        console.log(err.stack);
        return;
    }
    console.log('Search push suceeded: ' + data);
    return data;
}).promise();

snsPromises.push(snsResult)
await Promise.all(snsPromises)

希望能像我一样帮助通过Google偶然发现这一问题的人!

答案 1 :(得分:2)

stackdave会真正等待吗?

Necevil“成功执行的搜索推送将被记录两次”,因为您通过传递回调和使用Promise来混合调用操作。您应该只使用一种获取结果的方法

let snsResult = await sns.publish({
    Message: snsPayload,
    MessageStructure: 'json',
    TargetArn: endPointArn}).promise()

会成功的

答案 2 :(得分:1)

你可以简单地使用回调。像这样修改你的sendMessge

function sendMessage(message, phoneNumber, cb) {
    const params = { 
        Message: message, 
        MessageStructure: "string", 
        PhoneNumber: "+1" + phoneNumber
    };
    sns.publish(params, cb);
}

然后在您的主文件上,您可以像这样提供callback

if (userProfile) {
  const message = "Your username is:\n" + userProfile.username;
  AWSSNSClient.sendMessage(message, phoneNumber, (err, data) => {
    if (err) {
      result.error = setTitleAndMessage("Error", "An error occurred");
    }
    else {
      result.success = setTitleAndMessage("Success", "Message sent");
    }
    res.send(result);
  });
}

答案 3 :(得分:1)

这里是正确更新的API,2018年8月,Necevil回答两次发送短信。

// using config.env
AWS.config.region = 'eu-west-1';
AWS.config.update({
  accessKeyId: process.env.AMAZON_SMS_ID,
  secretAccessKey: process.env.AMAZON_SMS_TOKEN,
});

// parameters 
let params = {
   Message: contentSMS,  // here your sms
   PhoneNumber: mobile,  // here the cellphone
 };


 const snsResult = await sns.publish(params, async (err, data) => {
    if (err) {
       console.log("ERROR", err.stack);
    }
    console.log('SNS ok: ' , JSON.stringify (data));
  });

答案 4 :(得分:0)

如果您在发送重复的SNS消息时遇到问题,我通过利用AWS的示例解决了此问题:

// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
AWS.config.update({region: 'REGION'});

// Create publish parameters
var params = {
  Message: 'MESSAGE_TEXT', /* required */
  TopicArn: 'TOPIC_ARN'
};

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

// Handle promise's fulfilled/rejected states
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);
  });

通过使用传统的.then(),我可以解决上面评论中提到的重复消息错误。

答案 5 :(得分:0)

你可以创建一个使用promise方法的异步函数

async function sendMessage(message, phoneNumber){
     const params = { 
        Message: message, 
        PhoneNumber: phoneNumber
    };
  
 return new Promise((resolve, reject) => {
    SNS.publish(params, (err, data) => {
      if (err) {
         console.log("Search Push Failed:");
        console.log(err.stack);
        return reject(err);
      } else {
            console.log('Search push suceeded:' + phoneNumber);
        return resolve(data);
      }
    })
    
    });
  
}

然后你可以打电话

var  s=  await sendMessage(message,phoneNumber);