【问题标题】:Wait for AWS SNS publish callback to return a value to calling method等待 AWS SNS 发布回调将值返回给调用方法
【发布时间】:2018-05-28 03:01:47
【问题描述】:

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

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 上添加等待,但该函数仍会在 send 设置为 true 之前返回。

我知道消息发送没有错误,因为我正在接收它们并且没有打印控制台日志。

【问题讨论】:

  • 与 Javascript 中的其他异步事物一样,您必须向 sendMessage 提供一个可以调用成功或错误的回调函数,或者返回一个在成功或错误时解析/拒绝的 Promise。

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


【解决方案1】:

今天通过 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)

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

【讨论】:

  • 这应该是公认的分析器,我们需要在末尾添加 .promise()
  • 一旦我收集了 Promise 并使用了 await Promise.all(snsPromises) 我就开始工作了。谢谢!
  • 我在使用 promise() stackoverflow.com/questions/60711134/… 时遇到了事件发布两次的问题。也很奇怪,使用promise()时还需要回调
【解决方案2】:

stackdave 真的会等吗?

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

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

会成功的

【讨论】:

  • 这正是我所需要的!非常感谢。
【解决方案3】:

您可以简单地为此使用回调。像这样修改你的 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);
  });
}

【讨论】:

  • 在 sendMessage 函数中,行“let sent = false;”不再需要在那里正确吗?
  • 是的,您可以删除该变量,因为它不再使用了。
  • 编辑了答案并删除了sent 变量。
  • 请注意,这只等待切换到 SNS。 SNS 实际上是异步传递消息的。
【解决方案4】:

这里是正确更新的 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));
  });

【讨论】:

  • 这也是我面临的问题(重复的 SNS 发布)。如果我在 (err, data) 部分之前遗漏了“异步”,由于某种原因,回调会被调用两次。我不知道为什么。但我的 Javascript 可能不是最新的。不过这似乎可行。
【解决方案5】:

如果您在发送重复的 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(),我能够消除上面 cmets 中提到的重复消息错误。

【讨论】:

  • 这看起来很简单。我试过了,我没有从数据中得到任何 consol.log 或错误。我处于异步状态:exports.handler = async(event, context) => 我需要等待吗?
  • 好的。如果我使用 await Promise.all(snsPromises) 将这个与 @Necevil 混合,我会得到我期望的所有 console.logs。 :-)
【解决方案6】:

你可以创建一个使用 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);

【讨论】:

  • 你确定在resolvereject前面需要return吗?
猜你喜欢
  • 1970-01-01
  • 2013-02-14
  • 1970-01-01
  • 2019-07-25
  • 1970-01-01
  • 2016-09-03
相关资源
最近更新 更多