Firestore云函数重放历史变更重复推送问题排查求助
问题根因
- 第二个云函数的触发判断逻辑存在缺陷:你仅校验了变更后文档(
snapshot.after)的task数组内是否存在run为true的任务,没有对比变更前文档(snapshot.before)的状态,只要文档发生任意写操作(哪怕是内容无变化的覆盖写),只要历史task里还有run=true的记录,就会重复触发消息推送。 - 第一个云函数触发的后端逻辑为全量写入用户所有仓库数据:用户重新登录后,后端执行的131个仓库批量写操作会触发所有对应
repositories文档的onUpdate事件,即使这些文档的内容和之前完全一致,也会触发云函数执行,和你观察到的「历史消息全量重放」现象完全吻合。
修复方案
调整第二个云函数的判断逻辑,仅当task.run是本次变更新增/从false变为true的场景下才推送消息,参考修改后的代码:
exports.observeRepositoryUpdate = functions.firestore .document("/data/{uid}/repositories/{repositoryId}") .onUpdate(async (snapshot) => { const repoBefore = snapshot.before.data() as Repository; const repoAfter = snapshot.after.data() as Repository; if (repoAfter.task == null || repoAfter.task.length == 0) { return; } // 仅校验本次变更新增的run=true的任务 const hasNewRunTask = repoAfter.task.some(afterTask => { // 匹配变更前对应task,判断是否本次才变为run=true const beforeTask = repoBefore.task?.find(t => t.id === afterTask.id); return afterTask.run && (!beforeTask || !beforeTask.run); }); if (hasNewRunTask) { await pubSubClient .topic("repository-update") .publish(Buffer.from(JSON.stringify(repoAfter))); } });
- 可选优化:如果你的全量仓库写入不需要触发repository更新事件,可以在批量写入仓库数据时增加一个忽略触发的标记字段(比如
ignoreTrigger: true),云函数判断到该字段时直接返回,写入完成后再移除该字段即可。 - 额外校验建议:任务执行完成后及时将
task.run改为false,避免后续无关的文档更新误触发推送。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

