部署Firebase定时股票数据云函数报Maximum call stack size exceeded错误
报错根因
部署时栈溢出的直接原因是在Cloud Functions服务端环境错误引入了Firebase客户端Web SDK:你代码里用的firebase/app、firebase/firestore是面向浏览器、移动端客户端设计的SDK,在Node.js服务端环境加载解析时会触发递归调用逻辑,直接导致函数部署阶段生成manifest时抛出Maximum call stack size exceeded错误。
除此之外你的代码还有几个会导致运行异常的问题:
- 日期计算逻辑写在函数全局作用域,只会在函数冷启动时执行一次,后续热启动的实例会一直复用第一次计算的日期,拉取到的永远是冷启动当天前一天的数据,不会每日更新
- 循环调用
setDoc时没有等待写入Promise完成,函数可能在数据写入Firestore之前就终止运行,导致数据丢失 - 3000条文档并发单条写入很容易触发Firestore写入限流,拉高运行报错概率
- 原cron表达式
12 00 * * *实际是每日0点12分触发,和你要的12点触发需求不符
修复方案
- 先卸载错误的客户端SDK,安装服务端专用的Firebase Admin SDK,在functions目录下执行命令:
npm uninstall firebase npm install firebase-admin
- 替换原有index.ts的代码,修正初始化逻辑、日期计算位置、写入逻辑,修复后完整代码如下:
import * as functions from "firebase-functions"; import axios from "axios"; import { getFirestore, Timestamp } from "firebase-admin/firestore"; import { format } from "date-fns"; import { initializeApp, getApps } from "firebase-admin/app"; // 初始化Admin SDK,加判断避免冷启动重复初始化报错 if (!getApps().length) { initializeApp(); } const db = getFirestore(); const API_KEY = "****************"; interface StockItem { clpr: string; srtnCd: string; } export const getStocks = functions .region("asia-northeast3") .pubsub.schedule("0 12 * * *") // 修正为每日首尔时间12点整触发 .timeZone("Asia/Seoul") .onRun(async (context) => { // 日期计算移到函数内部,每次触发重新计算最新日期 const today = new Date(); const yesterday = new Date(today); yesterday.setDate(yesterday.getDate() - 1); const basDt = format(yesterday, "yyyyMMdd"); // 拉取股票数据 const { data } = await axios.get( `https://api.odcloud.kr/api/GetStockSecuritiesInfoService/v1/getStockPriceInfo?numOfRows=3000&resultType=json&basDt=${basDt}&serviceKey=${API_KEY}` ); const stockList: StockItem[] = data.response.body.items.item; // 分批次写入,Firestore单批次写入上限为500条,这里取400留冗余 const BATCH_SIZE = 400; for (let i = 0; i < stockList.length; i += BATCH_SIZE) { const batch = db.batch(); const chunk = stockList.slice(i, i + BATCH_SIZE); chunk.forEach((item) => { const docRef = db.doc(`KRX/${item.srtnCd}`); batch.set(docRef, { day: Timestamp.fromDate(today), price: item.clpr }); }); await batch.commit(); } return null; });
补充说明
- Admin SDK在Cloud Functions环境中会自动读取运行时绑定的服务账号权限,不需要手动填写客户端那套firebaseConfig参数,初始化更简单,权限也更高
- 用批量写入(Batch Write)替代循环单条setDoc,既减少网络请求开销,也能避免并发写入触发限流
- 所有异步操作都加了await,保证所有数据写入完成后函数才会退出,不会丢数据
- 如果你确实需要每日0点12分触发,把schedule里的cron表达式改回
12 00 * * *即可
内容的提问来源于stack exchange,提问作者신범기
相关产品推荐
相关产品推荐

