You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
  });
});

关键修改点说明

  1. 独立生成消息对象:用createNotificationMessage函数为每个用户生成独立的消息,避免了原代码中同一个对象被多次修改导致的token覆盖问题。
  2. 收集所有Promise:用sendPromises数组保存每个send操作的Promise,确保不会遗漏任何一个发送请求。
  3. 用Promise.all等待全部完成:返回Promise.all(sendPromises)让云函数等待所有通知处理完毕,彻底解决提前终止的问题。
  4. 增加token有效性检查:避免向没有token的用户发送无效请求,减少错误日志。
  5. 容错处理:单个用户发送失败时,返回Promise.resolve()保证其他用户的通知不受影响(如果需要单个失败就终止所有操作,可以删除这行)。

内容的提问来源于stack exchange,提问作者enfix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:41:31