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

设备未接收Firebase通知时触发SMS通知的实现方案咨询

实现思路与方案

核心改进方向

要实现超时未送达触发SMS的逻辑,关键是把FCM推送行为与通知状态追踪绑定,通过服务端的延迟检查机制来触发兜底的SMS通知。以下是具体可落地的方案:


一、基础改造:绑定通知标识与状态

  1. 给每个通知生成唯一ID
    在服务端处理React网页的POST请求时,先生成一个唯一的notificationId(可用UUID),同时将以下信息存入数据库:

    • notificationId:唯一标识
    • targetDeviceId:目标设备的FCM token
    • phoneNumber:目标用户的手机号(用于SMS)
    • content:通知内容
    • status:初始值设为pending(待送达)
    • expireAt:超时时间(比如当前时间+5分钟)
  2. FCM推送时携带通知ID
    调用Firebase的getMessaging().send()方法时,把notificationId放在通知的data字段中:

    // Node.js服务端代码示例
    const message = {
      token: targetDeviceId,
      notification: { title: '交易通知', body: content },
      data: { notificationId: 'xxx-xxx-xxx' } // 携带唯一ID
    };
    await getMessaging().send(message);
    
  3. 客户端接收后更新状态
    Flutter客户端在onMessage和onBackgroundMessage回调中,提取notificationId,调用服务端接口将对应通知的status更新为delivered(已送达)。


二、服务端超时检查机制(两种可选方案)

方案1:延迟队列(推荐,精准控制超时时间)

用Node.js的队列库(如BullMQ、Agenda)实现延迟任务,确保超时时间到了就触发检查:

  • 发送FCM的同时,将notificationId加入延迟队列,延迟时间设为你指定的超时时长(比如5分钟)。
  • 队列任务触发时,执行以下逻辑:
    1. 查询数据库中该notificationId的status。
    2. 如果状态还是pending,调用SMS服务商的API发送短信,然后将状态更新为sms_sent。
    3. 如果状态已经是delivered,直接跳过任务。

示例代码(BullMQ):

const { Queue, Worker } = require('bullmq');

// 创建延迟队列
const notificationQueue = new Queue('notification-check');

// 发送FCM后添加延迟任务
await notificationQueue.add('check-status', { notificationId }, { delay: 5 * 60 * 1000 });

// 处理队列任务的Worker
const worker = new Worker('notification-check', async job => {
  const { notificationId } = job.data;
  const notification = await db.collection('notifications').findOne({ notificationId });
  
  if (notification?.status === 'pending') {
    // 调用SMS接口发送短信
    await smsService.send(notification.phoneNumber, notification.content);
    // 更新状态
    await db.collection('notifications').updateOne(
      { notificationId },
      { $set: { status: 'sms_sent' } }
    );
  }
});

方案2:定时扫描数据库(实现简单,适合小流量场景)

用node-schedule等定时任务库,定期扫描数据库中超时且未送达的通知:

  • 配置定时任务(比如每分钟执行一次),查询status = pending且expireAt < 当前时间的通知。
  • 对符合条件的通知批量触发SMS发送,并更新状态。

示例代码:

const schedule = require('node-schedule');

// 每分钟执行一次扫描
schedule.scheduleJob('* * * * *', async () => {
  const expiredNotifications = await db.collection('notifications').find({
    status: 'pending',
    expireAt: { $lt: new Date() }
  }).toArray();

  for (const notification of expiredNotifications) {
    await smsService.send(notification.phoneNumber, notification.content);
    await db.collection('notifications').updateOne(
      { notificationId: notification.notificationId },
      { $set: { status: 'sms_sent' } }
    );
  }
});

三、替代方案(利用Firebase生态)

如果不想自己维护队列或定时任务,可以用Firebase Cloud Functions结合Firestore的TTL索引:

  1. 将通知数据存在Firestore,给expireAt字段设置TTL索引(过期自动删除文档)。
  2. 编写Cloud Function监听Firestore的文档删除事件,当文档被删除时,检查该通知是否已标记为delivered(可以在文档中存状态)。
  3. 如果未送达,调用SMS接口发送通知。

注意:Firestore的TTL触发可能有一定延迟(最长几小时),适合对超时时间要求不严格的场景。


四、关键容错处理

  • SMS重试机制:如果SMS发送失败,设置最多3次重试,每次间隔1分钟,避免服务商接口波动导致漏发。
  • 日志记录:记录FCM发送、状态更新、SMS发送的时间和结果,方便后续排查问题。
  • 状态幂等性:服务端更新状态的接口要保证幂等,避免客户端重复调用导致状态混乱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 16:40:27