Node.js Puppeteer触发MaxListenersExceededWarning警告如何解决
(node:21888) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 SIGINT listeners added to [process]. Use emitter.setMaxListeners() to increase limit.
该警告是Node.js的EventEmitter默认安全机制触发:同一事件类型默认最多允许绑定10个监听器,超出后就会抛出内存泄漏预警。你场景下是每个浏览器实例启动时,默认都会给process对象绑定一个SIGINT监听器用于在进程中断时自动清理浏览器进程,12个实例就会绑定12个监听器,超出默认上限。
除用完后移除对应监听器之外,还有以下可行解决方案:
调整process事件监听器上限
如果你确认当前监听器数量是业务正常需要、不存在泄漏风险,可以直接上调SIGINT事件的监听器上限,上限值设置为略高于你最大并行浏览器实例数即可,示例代码:// 比如你最大并行数为15,设置上限为20,预留冗余 process.setMaxListeners(20, 'SIGINT') // 也可以全局调整所有事件的上限,不推荐 // process.setMaxListeners(20)注意:不要直接将上限设置为
Infinity,否则真的出现监听器泄漏时不会有任何预警,提升排查成本复用全局唯一的SIGINT监听器
从根源减少监听器数量:不要给每个浏览器实例单独绑定SIGINT监听,全局维护一个活跃浏览器实例的集合,仅绑定1次SIGINT监听器,收到中断信号时遍历集合关闭所有存活的实例即可,既不会触发警告,也完全没有泄漏风险。禁用浏览器实例内置的SIGINT自动监听
主流浏览器自动化工具(Puppeteer/Playwright等)的启动配置中,都提供了关闭内置进程信号监听的参数,启动实例时传入对应参数即可避免工具自动绑定监听器:// Puppeteer 示例 const browser = await puppeteer.launch({ handleSIGINT: false }) // Playwright 示例 const browser = await playwright.chromium.launch({ handleSIGINT: false })禁用后你可以自己实现全局统一的进程信号处理逻辑,管控所有实例的生命周期。
池化控制浏览器实例最大并行数
你可以通过实例池技术限制同时运行的浏览器实例数量不超过默认监听器上限(10),既不会触发警告,也能避免开过多实例占满CPU/内存资源导致性能下降。可以直接使用开源的实例池工具,也可以自己基于队列实现简单的池化逻辑。
内容的提问来源于stack exchange,提问作者Jason Attwood

