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

Cloud Function定时触发偶发不发送FCM通知的原因及解决方案咨询

问题根因

  1. 异步任务未正确返回是核心问题
    你当前代码中的Firestore读写、FCM推送均为异步Promise操作,但函数末尾直接return null,Cloud Function接收到返回值后会立即冻结运行实例,不会等待未完成的异步任务执行。之前偶发发送成功只是刚好异步任务在实例被冻结前执行完毕,绝大多数情况下任务会被强制中断,自然没有后续日志、也不会发出通知。
  2. 无执行记录与冷启动无关
    冷启动只会导致函数执行延迟,只要定时触发器正常触发,哪怕冷启动失败也会生成错误日志。完全没有执行记录首先排查两个问题:
    • 你设置的定时时区为Europe/Berlin,确认日志查询的时间范围和柏林时区上午10点对应,避免时区换算错误漏掉执行记录
    • 进入Cloud Scheduler控制台,确认对应定时任务状态为启用,未被意外关闭

修复方案

1. 修复异步逻辑返回

调整代码,返回完整的Promise链,让Cloud Function等待所有任务执行完成后再回收实例,修改后代码参考:

const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp()

exports.qFunction = functions.region('europe-west3').pubsub.schedule('0 10 * * *').timeZone("Europe/Berlin").onRun((context) => {
    // 返回完整Promise链,不要提前return null
    return admin
      .firestore()
      .collection('users')
      .doc('hb')
      .get()
      .then((userDoc) => {
          const token = userDoc.data().tokens
          console.log(`Found user token: ${token}`)

          const now = new Date();
          const start = new Date(now.getFullYear(), 0, 0);
          const diff = (now - start) + ((start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000);
          const oneDay = 1000 * 60 * 60 * 24;
          let day = Math.floor(diff / oneDay) + 1;
          console.log('Day of year: ' + day);
          
          return admin
          .firestore()
          .collection('quotes')
          .doc(day.toString())
          .get()
          .then((quoteDoc) => {
            const payload = {
                notification: {
                  title: "HB",
                  body: quoteDoc.data().quote,
                  badge: '1',
                  sound: 'default'
                }
              }

              return admin
              .messaging()
              .sendToDevice(token, payload)
              .then(response => {
                console.log('Successfully sent message:', response)
                return null;
              })
              .catch(error => {
                console.log('Error sending message:', error)
                throw error;
              })
          })
      })
      .catch(err => {
        console.error('Function execution failed: ', err)
        throw err;
      })
  });

2. 可选冷启动优化(你的场景非必须)

当前仅服务1个用户、每日仅触发一次的场景下,冷启动对业务没有明显影响,不需要额外优化。如果需要进一步降低执行延迟,可以配置函数最小实例数为1,保持实例常驻,注意该配置会产生额外的运行费用。

3. 无执行记录排查

如果修改代码后仍有完全没有执行记录的问题,可以进入Cloud Scheduler控制台找到对应任务,手动触发一次验证执行链路是否正常。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 10:06:03