puppeteer-cluster icon indicating copy to clipboard operation
puppeteer-cluster copied to clipboard

MaxListenersExceededWarning: Possible EventEmitter memory leak detected

Open krunalshah68 opened this issue 6 years ago • 4 comments

Just came across a memory leak issue which hangs the program after some time.

concurrency: Cluster.CONCURRENCY_BROWSER,
workerCreationDelay: 200,
maxConcurrency: 20

krunalshah68 avatar Nov 28 '18 10:11 krunalshah68

Thanks for reporting, this definitely needs investigation.

thomasdondorf avatar Jan 03 '19 09:01 thomasdondorf

On each launch() function called, 4 events have been adding to NodeJS's process

const listeners = [helper.addEventListener(process, 'exit', killChrome)];
if (handleSIGINT)
    listeners.push(helper.addEventListener(process, 'SIGINT', () => {
        killChrome();
        process.exit(130);
    }));
if (handleSIGTERM)
    listeners.push(helper.addEventListener(process, 'SIGTERM', gracefullyCloseChrome));
if (handleSIGHUP)
    listeners.push(helper.addEventListener(process, 'SIGHUP', gracefullyCloseChrome));

When puppeteer-cluster launch a lot of Worker, NodeJS will show MaxListenersExceededWarning error

FYI: https://nodejs.org/api/events.html#events_eventemitter_defaultmaxlisteners

By default, a maximum of 10 listeners can be registered for any single event. .. EventEmitters will print a warning if more than 10 listeners are added for a particular event. This is a useful default that helps finding memory leaks.

You can easily disable this warning by using process.setMaxListeners(n) with n=20 in your case or more.

https://github.com/GoogleChrome/puppeteer/issues/594

For advanced use, you can remove all event listeners exit added by Puppeteer. And do some stuff like killChrome() and gracefullyCloseChrome() by yourself.

Note that 3 events SIGINT, SIGTERM, SIGHUP can be disabled in launch() options. Work in my case

const browser = await puppeteer.launch({
    handleSIGINT = false,
    handleSIGTERM = false,
    handleSIGHUP = false,
});

hashtafak avatar Jan 14 '19 20:01 hashtafak

Note that 3 events SIGINT, SIGTERM, SIGHUP can be disabled in launch() options. Work in my case

const browser = await puppeteer.launch({
    handleSIGINT = false,
    handleSIGTERM = false,
    handleSIGHUP = false,
});

FYI, most process managers use at least one of those signals to "ask" the process to terminate nicely. For example, systemd would send SIGTERM followed by SIGINT 90 seconds later (default behavior). Disabling them without explicitly call killChrome or gracefullyCloseChrome may spawn zombie processes.

raising max listeners to match worker count would be the safest workaround. As an added bonus, you could register additional listeners to do resource cleanup when the signal received.

bangbambang avatar Jan 30 '19 02:01 bangbambang

For me removing '--single-process', from args fixed the issue

puppeteerOptions: {
    headless: true,
    args: [
        // '--single-process',
    ],
}

mastershaig avatar Apr 07 '21 21:04 mastershaig