我正在开发一个nodejs应用程序(使用express),它将通过HTTP为客户端提供REST调用。其中一个REST API将处理POST请求,该请求将从POST主体获取数据并通过MQTT客户端发布(作为应用程序的一部分启动)。
订阅主题的单独应用程序(通过我们都连接到的MQTT代理)我发布到将接收消息并通过向我的应用程序的MQTT客户端订阅的主题发布消息来响应(这将导致回调以在我的Javascript应用程序中触发。)
我希望能够在我的应用程序正在处理的POST响应中返回我的应用程序收到的MQTT消息。
在常规的“C语言编程”术语中......有一个处理REST API的线程和一个处理接收MQTT消息的独立线程(例如两个不同的套接字)。我想阻塞处理信号量上的POST处理线程的线程,直到MQTT线程可以接收一些数据,将其排队并释放信号量以解除对POST处理线程的阻塞(然后将消息出列并将其返回到POST回复)。
在修改各种模块和Promise / Generators之后,我不清楚如何让它工作......
这样做的“javascript方式”是什么?
TIA!
答案 0 :(得分:1)
你没有在node.js中阻止。通过它的设计,node.js是事件驱动的,并且所有网络I / O(以及大多数文件I / O)都是非阻塞和异步的。因此,您需要协调多个异步操作,并在两者完成时得到通知(带有某种事件)。
当你没有共享任何代码时,很难非常具体,但是现在协调异步操作的主要工具是承诺。因此,如果您使每个异步操作返回一个将在异步操作完成时解析的promise或在异步操作遇到错误时拒绝,那么您可以使用Promise.all()
两个promise,它会告诉您当两个异步操作都完成并为你提供两个结果时。
一般的想法是:
let p1 = asyncOperation1(...);
let p2 = asyncOperation2(...);
Promise.all([p1, p2]).then(results => {
// both async operations are done here
// results[0] and results[1] contain the resolved value of each of the two promises
}).catch(err => {
// process error here
});
为了从REST操作获得承诺,有许多不同的解决方案,从手动执行您自己的运营承诺包装,到包装请求模块的模块,向像Bluebird这样具有.promisify()
的库提供承诺和.promisifyAll()
方法为您自动包装操作。要提供有关如何从异步操作中获得承诺的更具体信息,您必须与您分享实际代码。
因为看起来你是新来的,让我提供一些发布建议。如果您向我们展示您的代码,我们将始终能够提供更完整和更相关的答案。当你没有向我们展示你的代码时,你实际上是在寻求一个通用的教程,这个教程要写得多,而且更难以确保它涵盖你的确切用例。
答案 1 :(得分:1)
最终发现我可能已经在考虑解决方案......
在POST处理回调中,我将响应对象排入队列并返回。稍后,在MQTT订阅消息处理回调中,我将挂起的响应对象出列,并使用它向挂起的POST事务发送正确的响应。
答案 2 :(得分:0)
请勿阻止,在您发布的邮件中包含唯一ID,并且响应邮件也包含此ID。
然后使用此id作为密钥将快速响应对象存储在对象中,以便当响应到达并发回响应时。
您还应该包含一个时间戳,以便您可以定期遍历等待的响应对象,并在MQTT消息未及时到达时进行响应。
var onGoingRequests = {};
var id = 0;
mqttClient.on('message',function(topic,message){
var payload = JSON.parse(message.toString());
var details = onGoingRequest[payload.id];
if (details) {
details.response.status(200).send(details.body);
delete onGoingRequests[payload.id];
} else {
//response too late
}
});
app.post('/foo', function(req, resp) {
var message = {
id: 'foo' +id++,
body: req.body
}
var topic = 'request/foo';
mqttClient.publish(topic, JSON.stringify(message));
onGoingRequests[message.id] = {
response: resp,
timestamp: Date.now(),
};
});
var timeout = setInterval(function(){
var now = Date.now();
var keys = Object.keys(onGoingCommands);
for (key in keys){
var waiting = onGoingCommands[keys[key]];
if (waiting) {
var diff = now - waiting.timestamp;
if (diff < timeout) {
waiting.res.status(504).send('{"error": "timeout"}');
delete onGoingCommands[keys[key]];
}
}
}
}, 500);