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

Firebase定时函数获取Firestore随机文档代码偶发无响应

问题分析与修复方案

你的定时函数偶尔卡住的核心原因有两个:

  1. 云函数提前终止:你在newQuestions这个async函数里使用了.then()但没有等待Promise完成,Firebase云函数会在事件处理函数执行完毕后立即停止运行,导致后续的Firestore查询操作还没完成就被中断,所以日志只输出到"random key done"。
  2. Promise未处理边界情况:当两次查询(>=key和<key)都没有匹配文档时,你的代码没有调用reject,导致Promise一直处于pending状态,函数也无法正常结束。

修复后的代码

const { onSchedule } = require("firebase-functions/v2/scheduler");
const { logger } = require("firebase-functions");
const admin = require("firebase-admin");

admin.initializeApp();
const db = admin.firestore();

async function getRandomFromCollection(collection, level, enabled) {
  logger.info("Starting random search");
  const key = collection.doc().id;
  logger.info("random key done");

  // 第一次查询:>=随机key的文档
  let snapshot = await collection
    .where("enabled", "==", enabled)
    .where("level", "==", level)
    .where("__name__", ">=", key)
    .limit(1)
    .get();

  if (snapshot.size > 0) {
    logger.info("done");
    return snapshot.docs[0];
  }

  // 第二次查询:<随机key的文档
  snapshot = await collection
    .where("enabled", "==", enabled)
    .where("level", "==", level)
    .where("__name__", "<", key)
    .limit(1)
    .get();

  if (snapshot.size > 0) {
    logger.info("done");
    return snapshot.docs[0];
  }

  // 两次都没找到,抛出错误
  logger.info("No matching documents found");
  throw new Error("No documents matching the criteria");
}

exports.newQuestions = onSchedule(
  {
    schedule: "every day 9:55",
    maxInstances: 1,
    timeZone: "UTC",
  },
  async (event) => {
    try {
      const collection = db.collection("questions");
      const doc = await getRandomFromCollection(collection, 1, false);
      logger.info("Got question");
      // 这里可以添加处理doc的逻辑
    } catch (err) {
      logger.error(`ERROR! Something went wrong when generating question! Error: ${err}`);
    }
  }
);

关键修复点

  • 使用async/await替代嵌套.then:让代码逻辑更清晰,同时确保所有异步操作都被等待,避免函数提前终止。
  • 等待Promise完成:在newQuestions函数里用await调用getRandomFromCollection,确保云函数等到所有操作完成后再结束。
  • 处理无匹配文档的情况:当两次查询都没有结果时,主动抛出错误,避免Promise一直pending。
  • 简化文档获取:用snapshot.docs[0]代替forEach,因为limit(1)最多只会返回一个文档,更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 17:47:22