我正在努力使用javascript / Nodejs8 Google Cloud Function将有效负载发布到Google PubSub。
所以我有一个由HTTP请求触发的Cloud Function,然后将请求主体发布到pubsub主题(配置为拉模式)。
这是我的代码:
const {PubSub} = require('@google-cloud/pubsub');
const pubsub = new PubSub();
const topic = pubsub.topic('my-fancy-topic');
function formatPubSubMessage(reqObj){
// the body is pure text
return Buffer.from(reqObj.body);
};
exports.entryPoint = function validate(req, res) {
topic.publish(formatPubSubMessage(req)).then((messageId) => {
console.log("sent pubsub message with id :: " + messageId)
});
res.status(200).json({"res":"OK"});
};
我的问题是,在发布pubsub消息之前,云功能完成了执行(在日志中,“我的pubsub日志”之前大约30或40秒出现了“函数执行了X毫秒,状态代码为200”的日志) 。我也有几次带有“忽略已完成功能的异常”的日志,但没有得到pubsub日志)
我不是javascript或nodejs专家,我也不精通javascript promises,但是我想知道是否可以使发布同步。我也在想,我可能在这里做错了!
预先感谢您的帮助。
答案 0 :(得分:1)
按照您的逻辑,当HTTP消息到达时,将调用回调/事件处理函数。然后,您执行publish()函数。执行发布是异步活动。这意味着发布需要花费一些时间才能完成,并且由于JavaScript(本质上)不想阻塞,因此它会立即返回,并承诺在异步工作完成后可以通知您。在执行publish()之后,您的逻辑立即执行res.status(....),该响应发送对HTTP请求的响应,这实际上是来自HTTP客户端的流请求的结尾。异步发布仍在进行中,当异步发布本身完成时,就会发生发布的回调并记录响应。
不幸的是,这不是Google在此处记录的好习惯...
https://cloud.google.com/functions/docs/bestpractices/tips#do_not_start_background_activities
在最后一个故事中,您调用的validate
函数将在完成发布之前结束。如果要在publish()执行时阻塞(有效地使其同步),则可以使用JavaScript await
关键字。松散地是这样的:
try {
let messageId = await topic.publish(....);
console.log(...);
catch(e) {
...
}
您还需要将功能标记为async
。例如:
exports.entryPoint = async function validate(req, res) {
...
请参阅:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
您还可以从函数中简单地返回一个Promise,并且直到整个Promise都解决后,回调函数才被视为已解决。
最重要的是深入研究承诺。
答案 1 :(得分:0)
现在,此代码在发布完成之前 发送响应。发送响应后,该功能将终止,正在进行的异步工作可能无法完成。
您应该做的是仅在发布完成后才发送响应,这意味着将代码行放入then
回调中。
exports.entryPoint = function validate(req, res) {
topic.publish(formatPubSubMessage(req)).then((messageId) => {
console.log("sent pubsub message with id :: " + messageId)
res.status(200).json({"res":"OK"});
});
};
我建议花一些时间来学习诺言的工作方式,因为这对于构建可以正常工作的功能至关重要。