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

Stripe Webhook触发的Cloud Function写入Firestore延迟排查求助

Google Cloud Function处理Stripe Webhook时Firestore查询/写入延迟排查

我有一个Google Cloud Function(代码如下),用于接收Stripe支付Webhook并将部分数据写入Firestore。但函数会卡住约3分钟才完成,添加日志后发现延迟出现在根据Stripe返回的customer_id查询对应client文档的环节。该集合仅含4条数据,不存在大集合或索引问题。后续已为invoicePaymentsRef.add(data)添加await,但写入Firestore仍有延迟,请求排查原因。

const Stripe = require("stripe");
const admin = require("firebase-admin");

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
  apiVersion: "2023-10-16",
});
if (admin.apps.length === 0) {
  admin.initializeApp();
}
const db = admin.firestore();

async function webhook(request, response) {
  const sig = request.headers["stripe-signature"];

  let event;

  try {
    event = stripe.webhooks.constructEvent(
      request.rawBody,
      sig,
      process.env.WEBHOOK_SECRET
    );
  } catch (err) {
    console.error("⚠️ Webhook signature verification failed.", err.message);
    return response.status(400).send(`Webhook Error: ${err.message}`);
  }

  switch (event.type) {
    case "checkout.session.completed":
      handlepaymentCompletion(event.data.object);

      break;
    default:
      // Unexpected event type
      return response.status(400).end();
  }

  // Return a response to acknowledge receipt of the event
  response.json({ received: true });
}

//  handle sub created

async function handlepaymentCompletion(payment) {
  try {
    const lineItems = await stripe.checkout.sessions.listLineItems(
      payment?.id,
      {
        limit: 100,
      }
    );
    console.log(lineItems.data);

    /// Assuming there's only one item
    const item = lineItems.data[0];

    // Construct the data object for Firestore
    const data = {
      amount: item.amount_total,
      currency: item.currency,
      description: item.description,
      active: item.price.active,
      created: payment.created,
      product: item.price.product,
      paymentIntentId: payment.payment_intent,
    };

    const customer_id = payment.customer;

    // Query for the client document with the matching `stripeCusId`
    const clientQuerySnapshot = await db
      .collection("productionClients")
      .where("stripeCustId", "==", customer_id)
      .get();

    if (!clientQuerySnapshot.empty) {
      const clientId = clientQuerySnapshot.docs[0].id;

      // Reference to the invoicePayments sub-collection
      const invoicePaymentsRef = db
        .collection("productionClients")
        .doc(clientId)
        .collection("invoicePayments");

      // Example: Here's how you could add a new invoice payment document
      await invoicePaymentsRef.add(data);

      console.log("Invoice payment updated successfully.");
    } else {
      console.log("No client found with the specified Stripe customer ID.");
    }
  } catch (error) {
    console.error("Error updating user:", error);
    // Optionally handle the error
  }
}

module.exports = webhook;

相关日志/代码调整说明

  • 原函数日志:显示Firestore查询环节存在显著延迟,函数整体耗时约3分钟
  • 添加await后的代码调整:在调用handlepaymentCompletion时补充了await关键字
  • 添加await后的日志:Firestore操作延迟问题仍未解决,函数完成时长依旧偏长

排查方向及解决方案

1. 修复Webhook异步调用逻辑

原代码中webhook函数调用handlepaymentCompletion时未加await,导致函数提前返回响应,异步任务在后台执行时可能因Cloud Function资源回收机制被延迟调度。修改代码:

case "checkout.session.completed":
  await handlepaymentCompletion(event.data.object);
  break;

2. 优化Firestore查询效率

虽然集合数据量小,但可做以下优化:

  • 确认stripeCustId字段的单字段索引状态(Firestore控制台→索引→复合索引,检查自动生成的单字段索引是否正常)
  • 若业务允许,将client文档ID直接设为Stripe customer_id,用db.collection("productionClients").doc(customer_id).get()替代where查询,跳过索引匹配环节

3. 排查Stripe API调用延迟

添加耗时日志确认Stripe API调用是否拖慢整体流程:

console.time("stripe_line_items");
const lineItems = await stripe.checkout.sessions.listLineItems(payment?.id, { limit: 100 });
console.timeEnd("stripe_line_items");

4. 调整Cloud Function运行配置

  • 提升函数内存分配:默认256MB内存可能导致IO性能不足,建议调整为512MB或1GB,同时会提升CPU配额
  • 确保函数区域与Firestore数据库区域一致:跨区域调用会增加网络延迟,尽量保持同区域部署

5. 精准定位延迟节点

在handlepaymentCompletion关键环节添加耗时日志,明确是查询还是写入环节出问题:

console.time("firestore_query");
const clientQuerySnapshot = await db.collection("productionClients").where("stripeCustId", "==", customer_id).get();
console.timeEnd("firestore_query");

console.time("firestore_write");
await invoicePaymentsRef.add(data);
console.timeEnd("firestore_write");

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 09:55:56