Firebase云函数向多FCM令牌发消息丢失,Promise处理咨询
你说得完全对——问题确实出在Promise的处理上!当前你的云函数在遍历用户列表发送通知时,没有等待所有admin.messaging().send()的异步操作完成就结束了,这会导致云函数提前终止,部分通知还没发送就被中断,自然会出现用户收不到的情况。
问题根源
云函数的生命周期是由你返回的Promise控制的:你现在返回的是query.once("value")的Promise,但里面的send调用都是“火并忘记”的异步操作——云函数会在用户查询完成后立刻结束,根本不会等这些通知发送完毕。
解决方案:等待所有发送操作完成
我们需要把所有admin.messaging().send()返回的Promise收集起来,用Promise.all()等待它们全部完成,再把这个组合后的Promise返回给云函数。这样云函数会一直等到所有通知都发送(或失败)后才会终止。
另外还要注意:原代码里直接修改同一个msg.message对象的token属性,会因为对象引用的特性,导致所有send调用最终使用最后一个用户的token,这也是一个潜在的bug,需要一起修复。
修改后的完整代码:
exports.sendMessage = functions.database.ref('/messages/{messageId}') .onCreate((snapshot, context) => { const original = snapshot.val(); // 封装消息生成逻辑,每个用户生成独立的消息对象 const createNotificationMessage = (token) => ({ data: { title: 'title2 test', body: 'body2 test', notify_type: 'chat_message', notify_id: Date.now().toString(), }, apns: { headers: { 'apns-priority': '10', 'apns-expiration': '0' }, payload: { aps: { contentAvailable: true, sound:'' }, 'acme1': 'bar', title: 'title test', body: 'body test', notify_type: 'chat_message', notify_id: Date.now().toString() } }, token: token }); return firebase.database().ref("users").once("value") .then(function(snapshot) { // 收集所有发送通知的Promise const sendPromises = []; snapshot.forEach(function(childSnapshot) { const user = childSnapshot.val(); const token = user.token; const username = user.username; // 先检查token是否存在,避免无效请求 if (token) { const message = createNotificationMessage(token); const sendPromise = admin.messaging().send(message) .then((response) => { console.log('message sent to '+username); return response; }) .catch((error) => { console.log(`Failed to send to ${username}:`, error); // 可选:如果希望单个失败不影响其他发送,就返回resolved的Promise return Promise.resolve(); }); sendPromises.push(sendPromise); } }); // 等待所有通知发送完成,再结束云函数 return Promise.all(sendPromises); }) .catch((error) => { console.log('Failed to fetch users:', error); return Promise.reject(error); }); });
关键修改点说明
- 独立生成消息对象:用
createNotificationMessage函数为每个用户生成独立的消息,避免了原代码中同一个对象被多次修改导致的token覆盖问题。 - 收集所有Promise:用
sendPromises数组保存每个send操作的Promise,确保不会遗漏任何一个发送请求。 - 用Promise.all等待全部完成:返回
Promise.all(sendPromises)让云函数等待所有通知处理完毕,彻底解决提前终止的问题。 - 增加token有效性检查:避免向没有token的用户发送无效请求,减少错误日志。
- 容错处理:单个用户发送失败时,返回
Promise.resolve()保证其他用户的通知不受影响(如果需要单个失败就终止所有操作,可以删除这行)。
内容的提问来源于stack exchange,提问作者enfix
相关产品推荐
相关产品推荐

