Firebase定时函数获取Firestore随机文档代码偶发无响应
问题分析与修复方案
你的定时函数偶尔卡住的核心原因有两个:
- 云函数提前终止:你在
newQuestions这个async函数里使用了.then()但没有等待Promise完成,Firebase云函数会在事件处理函数执行完毕后立即停止运行,导致后续的Firestore查询操作还没完成就被中断,所以日志只输出到"random key done"。 - 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
相关产品推荐
相关产品推荐

