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

如何处理JavaScript中Selenium崩溃?捕获异常后程序仍终止

Selenium长时间运行后崩溃问题处理方案

问题现象

Selenium服务长时间运行正常后突然崩溃,报错Process unexpectedly closed with status 0。已用catch块捕获Promise异常并打印错误,但程序仍会终止。此外还出现过不可复现的MaxListenersExceededWarning内存泄漏警告,重新运行相同输入时不会触发。

崩溃报错信息

A critical error was thrown while processing
        https://www.testtesttest.com/norwegian-english/snakk. Error was WebDriverError: Process unexpectedly closed with status 0
/opt/narjetas/node_modules/selenium-webdriver/lib/error.js:524
    let err = new ctor(data.message)
              ^

WebDriverError: Process unexpectedly closed with status 0
    at Object.throwDecodedError (/opt/narjetas/node_modules/selenium-webdriver/lib/error.js:524:15)
    at parseHttpResponse (/opt/narjetas/node_modules/selenium-webdriver/lib/http.js:587:13)
    at Executor.execute (/opt/narjetas/node_modules/selenium-webdriver/lib/http.js:515:28)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  remoteStacktrace: ''
}

当前错误捕获代码

getUrl(req.params.url, driver).then(html => {
    res.send(`${html}`);
    setTimeout(() => {
        console.info("INFO: Exiting driver.");
        
        driver.quit().catch(() => {
            console.error("ERROR: Failed to quit driver.");
        })
    }, 1000);
}).catch((error) => {
    console.error(`A critical error was thrown while processing 
    ${req.params.url}. Error was ${error}`);
    res.send('');
});

核心疑问

  1. 如何处理该Selenium错误,避免程序终止?
  2. 无固定触发场景的崩溃该如何排查?
  3. 如何优化Selenium使用方式,提升稳定性?

其他异常记录

(node:1156709) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 exit listeners added to [process]. Use emitter.setMaxListeners() to increase limit
(Use `node --trace-warnings ...` to show where the warning was created)

平台环境

[root@lab ~]# cat /etc/*-release
NAME="Red Hat Enterprise Linux"
VERSION="8.6 (Ootpa)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="8.6"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Red Hat Enterprise Linux 8.6 (Ootpa)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:redhat:enterprise_linux:8::baseos"
HOME_URL="https://www.redhat.com/"
DOCUMENTATION_URL="https://access.redhat.com/documentation/red_hat_enterprise_linux/8/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"

REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 8"
REDHAT_BUGZILLA_PRODUCT_VERSION=8.6
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="8.6"
Red Hat Enterprise Linux release 8.6 (Ootpa)
Red Hat Enterprise Linux release 8.6 (Ootpa)

[root@lab ~]# firefox --version
Mozilla Firefox 91.13.0esr

解决方案与优化建议

1. 阻止程序终止的错误处理

全局捕获未处理异常

添加全局异常捕获,避免未处理的Promise拒绝或uncaughtException直接终止程序,同时强制清理残留进程:

// 捕获未处理的Promise拒绝
process.on('unhandledRejection', (reason) => {
  console.error('未处理Promise拒绝:', reason);
  if (driver) {
    driver.quit().catch(() => {
      // 强制杀掉浏览器和驱动进程
      require('child_process').execSync('pkill -f firefox && pkill -f geckodriver');
    });
  }
});

// 捕获未捕获的同步异常
process.on('uncaughtException', (error) => {
  console.error('未捕获异常:', error);
  process.exitCode = 1;
  if (driver) {
    driver.quit().catch(() => {
      require('child_process').execSync('pkill -f firefox && pkill -f geckodriver');
    });
  }
});

完善Promise链捕获

确保所有异步操作都被捕获,包括getUrl内部的潜在异常,避免遗漏未处理的Promise。

2. 优化Selenium使用方式

避免复用driver实例

长时间复用driver易导致内存泄漏、进程异常,建议每次请求创建新driver实例,用完立即销毁:

async function handleRequest(req, res) {
  let driver;
  try {
    // 每次请求创建独立driver
    const options = new firefox.Options()
      .headless()
      .addArguments('--no-sandbox')
      .addArguments('--disable-dev-shm-usage');
    driver = await new Builder().forBrowser('firefox').setFirefoxOptions(options).build();
    
    const html = await getUrl(req.params.url, driver);
    res.send(html);
  } catch (error) {
    console.error(`处理${req.params.url}出错:`, error);
    res.send('');
  } finally {
    // 无论成功失败都销毁driver
    if (driver) {
      try {
        await driver.quit();
      } catch (e) {
        console.error('销毁driver失败,强制清理进程');
        require('child_process').execSync('pkill -f firefox && pkill -f geckodriver');
      }
    }
  }
}

解决EventEmitter内存泄漏

手动调整process的最大监听器数量,或排查代码中重复添加监听器的逻辑:

// 取消监听器数量限制(或设置为更大数值如20)
process.setMaxListeners(0);

优化浏览器启动参数

添加稳定性相关参数,减少资源占用:

const options = new firefox.Options()
  .headless() // 无头模式运行,节省资源
  .addArguments('--disable-gpu')
  .addArguments('--no-sandbox')
  .addArguments('--disable-dev-shm-usage') // 解决/dev/shm空间不足问题
  .addArguments('--memory-high=512') // 限制内存使用(单位MB)
  .addArguments('--disk-cache-size=102400'); // 限制缓存大小(单位KB)

3. 排查无固定触发场景的错误

增加日志粒度

在getUrl函数内部添加详细日志,记录每个操作阶段(导航、元素等待、源码获取等)的状态,定位崩溃节点:

async function getUrl(url, driver) {
  console.log(`开始导航至: ${url}`);
  await driver.get(url);
  console.log(`导航完成,当前URL: ${await driver.getCurrentUrl()}`);
  
  // 等待页面加载完成
  await driver.wait(until.elementLocated(By.tagName('body')), 10000);
  console.log(`页面元素加载完成`);
  
  const html = await driver.getPageSource();
  console.log(`获取页面源码完成`);
  return html;
}

捕获浏览器日志

获取浏览器控制台日志,排查是否由页面级错误导致崩溃:

// 在driver创建后启用日志捕获
driver.manage().logs().get('browser').then(logs => {
  logs.forEach(log => console.log(`浏览器日志[${log.level.name}]:`, log.message));
});

监控系统资源

定时记录系统和进程资源使用情况,排查是否因资源耗尽导致崩溃:

const os = require('os');
setInterval(() => {
  const processMem = process.memoryUsage();
  const systemMem = {
    total: Math.round(os.totalmem() / 1024 / 1024),
    free: Math.round(os.freemem() / 1024 / 1024)
  };
  console.log(`进程内存: ${Math.round(processMem.heapUsed / 1024 / 1024)}MB | 系统剩余内存: ${systemMem.free}/${systemMem.total}MB`);
}, 60000); // 每分钟记录一次

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 12:20:26