Cloud Function定时触发偶发不发送FCM通知的原因及解决方案咨询
问题根因
- 异步任务未正确返回是核心问题
你当前代码中的Firestore读写、FCM推送均为异步Promise操作,但函数末尾直接return null,Cloud Function接收到返回值后会立即冻结运行实例,不会等待未完成的异步任务执行。之前偶发发送成功只是刚好异步任务在实例被冻结前执行完毕,绝大多数情况下任务会被强制中断,自然没有后续日志、也不会发出通知。 - 无执行记录与冷启动无关
冷启动只会导致函数执行延迟,只要定时触发器正常触发,哪怕冷启动失败也会生成错误日志。完全没有执行记录首先排查两个问题:- 你设置的定时时区为
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
相关产品推荐
相关产品推荐

