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

Firebase云函数用Puppeteer截图触发256MB内存超限问题排查

Firebase Cloud Function + Puppeteer 内存超限与请求数异常排查

问题背景

创建了监听Firestore websites集合新增事件的Cloud Function,触发Puppeteer对目标网站截图,但频繁触发256MB内存限制错误。Puppeteer启动耗时极久(数分钟级),日志显示启动完成后出现内存超限,且存在处理1次或2次请求就触发错误的情况,怀疑和异步函数特性有关。

相关代码

云函数完整代码

exports.onWebsiteCreateTakeScreenshot = functions.firestore
    .document('websites/{id}')
    .onCreate(async (snap, context) =>{
      const webpageDocRef = admin.firestore().collection("websites").doc(context.params.id);
      webpageDocRef.get().then(async (snapshot) => {
        if (!snapshot.empty) {
          const url = snapshot.data()["url"];

          try {
            console.log("Launching puppeteer");
            const browser = await puppeteer.launch({
              headless: true,
              args: ["--no-sandbox"],
              timeout: 0,
            });
            console.log("puppeteer launch complete");
            const page = await browser.newPage();
            await page.setViewport({width: 640, height: 480});
            await page.goto(url, {waitUntil: 'networkidle2'});
            const bucket = admin.storage().bucket("thumbnails");
            const file = bucket.file(context.params.id + ".png");
            const screenshotBuffer = await page.screenshot();
            await file.save(screenshotBuffer);
            await browser.close();
          } catch (e) {
            console.error("Error: " + e);
          }
        } else {
          console.log("Error: No documents found");
        }
      });
    });

Puppeteer启动代码

const browser = await puppeteer.launch({
              headless: true,
              args: ["--no-sandbox"],
              timeout: 0,
            });

错误信息

Container worker exceeded memory limit of 256 MiB with 256 MiB used after servicing 2 requests total. Consider setting a larger instance class.

依赖信息(package.json片段)

"engines": { "node": "16" }, "main": "index.js", "dependencies": { "firebase-admin": "^10.0.2", "firebase-functions": "^3.18.0", "puppeteer" : "^18.2.1", "chromium" : "^3.0.3"

问题排查与解决方案

1. 内存超限原因

  • Chromium基础内存占用:无头模式下的Chromium本身启动和加载网页的内存开销较大,256MB默认实例内存对多数网页来说都偏紧张,尤其是包含大量图片、脚本的页面。
  • 异步逻辑错误导致内存泄漏:外层async函数内部使用.then()而非await,导致云函数主线程提前结束,Puppeteer进程可能未被正确关闭,残留内存占用无法释放。
  • 冗余依赖:同时安装puppeteer和chromium,Puppeteer已内置Chromium,额外的chromium包会造成资源重复加载,增加内存负担。
  • 资源释放不及时:仅关闭浏览器而未显式关闭页面,虽然理论上浏览器关闭会销毁页面,但提前关闭页面能更早释放内存。

2. 请求数异常与异步函数的关系

请求数显示处理2次但实际仅触发1次,核心原因是异步嵌套错误:

  • 云函数onCreate回调为async函数,但内部调用webpageDocRef.get().then(...)时未加await,导致函数主线程直接结束,Firebase判定执行完成,但.then()内的Puppeteer任务仍在后台运行。
  • 当函数实例被复用时,新触发的任务会和之前未完成的任务同时运行,同一个容器内叠加处理多个请求,内存占用瞬间超限。
  • 额外调用webpageDocRef.get()属于冗余操作,snap参数已包含新增文档数据,这一步不仅浪费资源,还加剧了异步嵌套的复杂度。

3. 具体优化方案

修复异步处理逻辑

去掉冗余的Firestore查询,用await替代.then(),确保函数等待所有任务完成后再结束:

exports.onWebsiteCreateTakeScreenshot = functions.firestore
  .document('websites/{id}')
  .onCreate(async (snap, context) => {
    let browser;
    try {
      const url = snap.data().url;
      console.log("Launching puppeteer");
      browser = await puppeteer.launch({
        headless: true,
        args: ["--no-sandbox", "--disable-dev-shm-usage", "--single-process"],
        timeout: 0,
      });
      console.log("puppeteer launch complete");
      const page = await browser.newPage();
      await page.setViewport({width: 640, height: 480});
      await page.goto(url, {waitUntil: 'networkidle2'});
      const bucket = admin.storage().bucket("thumbnails");
      const file = bucket.file(context.params.id + ".png");
      const screenshotBuffer = await page.screenshot();
      await file.save(screenshotBuffer);
      
      // 先关闭页面再关闭浏览器,尽早释放内存
      await page.close();
      await browser.close();
    } catch (e) {
      console.error("Error: " + e);
      // 出错时强制关闭浏览器,避免内存泄漏
      if (browser) await browser.close();
    }
  });

优化Puppeteer启动参数

  • --disable-dev-shm-usage:避免使用容器内有限的/dev/shm空间,改用临时文件,减少内存压力。
  • --single-process:以单进程模式运行Chromium,降低内存占用(注意:部分复杂页面可能存在兼容性问题)。

调整云函数实例配置

在firebase.json中配置更大的实例内存,比如512MB:

{
  "functions": {
    "runtimeOptions": {
      "memory": "512MB"
    }
  }
}

清理冗余依赖

卸载chromium包,仅保留puppeteer:

npm uninstall chromium

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 17:15:43