Nodejs8 GCP云函数同步发布PubSub消息问题求助
问题分析与解决方案
这个问题我太熟悉了!核心原因是你的云函数没有等待PubSub的异步发布操作完成就给客户端返回了响应,导致函数提前终止,后续的发布逻辑直接被中断了。这就是为什么你会看到日志里函数先结束,还出现“Ignoring exception from a finished function”,甚至消息发布失败的情况。
Node.js里不存在真正的“同步发布”(因为网络IO操作天生是异步的),但我们可以通过等待Promise完成,让代码逻辑上按顺序执行,确保消息发布完成后再结束函数。下面给你两种简单易懂的修复方案:
方案1:使用async/await(更直观,推荐)
Node.js 8已经支持async/await语法,我们可以把云函数入口改成异步函数,用await等待发布操作完成后再返回响应:
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 = async function validate(req, res) { try { // 等待PubSub消息发布完成 const messageId = await topic.publish(formatPubSubMessage(req)); console.log("sent pubsub message with id :: " + messageId); // 发布成功后再返回响应 res.status(200).json({"res":"OK"}); } catch (err) { // 处理发布失败的情况 console.error("Failed to publish message:", err); res.status(500).json({"res":"ERROR", "error": err.message}); } };
方案2:调整Promise链式调用(不用async/await的写法)
如果你更习惯用.then()的方式,只需要把返回响应的代码移到.then()的回调里,确保只有发布成功后才结束函数:
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"}); }) .catch((err) => { // 捕获发布失败的异常 console.error("Failed to publish message:", err); res.status(500).json({"res":"ERROR", "error": err.message}); }); };
为什么原来的代码不行?
你原来的代码里,topic.publish()返回一个Promise,你虽然调用了.then(),但没有等待这个Promise完成就直接执行了res.status(200)...。Cloud Functions看到响应发送后,立刻终止了函数进程,此时.then()里的回调可能还没执行,或者执行到一半就被中断,导致消息发布失败、日志顺序混乱。
内容的提问来源于stack exchange,提问作者R.E.B Hernandez
相关产品推荐
相关产品推荐

