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

Firebase函数中Firestore update的then回调触发两次问题求助

问题原因及解决方案

核心触发原因

按可能性从高到低排列如下:

  • Firestore Admin SDK 内置自动重试机制
    Firestore 默认对写操作开启了可重试错误的自动重试逻辑。当第一次update请求已经成功在Firestore服务端执行,但SDK侧因为网络抖动、临时超时没有及时收到服务端的成功响应时,会自动重试同一条update请求。如果重试请求也正常执行成功,就会触发两次then回调,打印两次CHECKPOINT B。由于update传入的参数完全相同,该操作本身是幂等的,不会导致数据异常。
  • 冗余Promise包装导致的边界异常
    你当前的代码对本身已经返回Promise的update方法额外包装了一层new Promise,属于典型的Promise反模式。虽然当前代码逻辑看起来没有明显问题,但这种写法会放大底层SDK的异常行为:如果Firestore SDK内部出现Promise被resolve两次的极端情况,外层自定义的Promise也会跟着触发两次回调。
  • Firebase日志系统偶发重复上报
    Firebase函数的日志收集服务本身也存在小概率的同一条日志重复上报的问题,你可以查看两条CHECKPOINT B日志的时间戳,如果时间戳完全一致,就属于日志系统的问题,和代码逻辑无关。

修复方案

// 去掉冗余的Promise包装,直接返回update方法的Promise即可
const setSubscriptionStateByStripeId = (
  suscriptionId: string,
  targetState: Stripe.Subscription.Status,
  stripeSubscription: Stripe.Subscription): Promise<void> => {
  functions.logger.info("CHECKPOINT A");
  const db = admin.firestore();
  return db.collection("subscriptions")
    .doc(suscriptionId)
    .update({
      state: targetState,
      stripeSubscription: stripeSubscription,
    })
    .then(() => {
      functions.logger.info("CHECKPOINT B");
    })
    .catch((err: Error) => {
      throw new Error("could not set subscription");
    });
};

如果修复后仍偶发出现两次CHECKPOINT B,且两次日志的时间戳存在明显间隔,就属于SDK自动重试的正常行为,不需要额外处理,不会影响业务数据正确性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 08:24:00