sindresorhus / grunt-concurrent

Run grunt tasks concurrently
MIT License
798 stars 66 forks source link

Memory leack in concurent build proccess. #104

Open syonfox opened 11 months ago

syonfox commented 11 months ago

Hi, i have been using this and just restarting in my dev proccess ;) but am trying to track down why my concurrent bundling is leaky. to tighten up the whole process. Does anyone have insight into this problem. I am watching many code files for different bundles

Running "concurrent:bundle" (concurrent) task
Verifying property concurrent.bundle exists in config...OK
Files: [no src] -> bundle
Options: limit=16, indent, logConcurrentOutput
>> Warning: There are more tasks than your concurrency limit. After this limit
>> is reached no further tasks will be run until the current tasks are
>> completed. You can adjust the limit in the concurrent task options
(node:22429) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 error listeners added to [WriteStream]. Use emitter.setMaxListeners() to increase limit
    at _addListener (node:events:587:17)
    at WriteStream.prependListener (node:events:619:14)
    at prependListener (/home/mango/git/plan-webmap/node_modules/readable-stream/lib/_stream_readable.js:92:69)
    at Pumpify.Readable.pipe (/home/mango/git/plan-webmap/node_modules/readable-stream/lib/_stream_readable.js:644:3)
    at /home/mango/git/plan-webmap/node_modules/grunt-concurrent/tasks/concurrent.js:70:15
    at /home/mango/git/plan-webmap/node_modules/grunt-concurrent/node_modules/async/dist/async.js:2588:44
    at replenish (/home/mango/git/plan-webmap/node_modules/grunt-concurrent/node_modules/async/dist/async.js:446:21)
    at /home/mango/git/plan-webmap/node_modules/grunt-concurrent/node_modules/async/dist/async.js:451:13
    at Object.eachLimit$1 (/home/mango/git/plan-webmap/node_modules/grunt-concurrent/node_modules/async/dist/async.js:2718:34)
    at Object.awaitable (/home/mango/git/plan-webmap/node_modules/grunt-concurrent/node_modules/async/dist/async.js:211:32)
    at Object.<anonymous> (/home/mango/git/plan-webmap/node_modules/grunt-concurrent/tasks/concurrent.js:38:9)
    at Object.<anonymous> (/home/mango/git/plan-webmap/node_modules/grunt/lib/grunt/task.js:252:15)
    at Object.thisTask.fn (/home/mango/git/plan-webmap/node_modules/grunt/lib/grunt/task.js:70:16)
    at Object.<anonymous> (/home/mango/git/plan-webmap/node_modules/grunt/lib/util/task.js:294:30)
    at Task.runTaskFn (/home/mango/git/plan-webmap/node_modules/grunt/lib/util/task.js:244:24)
    at Task.<anonymous> (/home/mango/git/plan-webmap/node_modules/grunt/lib/util/task.js:293:12)
    at /home/mango/git/plan-webmap/node_modules/grunt/lib/util/task.js:220:11
    at processTicksAndRejections (node:internal/process/task_queues:78:11)
(node:22429) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 error listeners added to [WriteStream]. Use emitter.setMaxListeners() to increase limit

Looking into this it might be related to https://github.com/node-fetch/node-fetch/issues/1295#issuecomment-921178548

//line 38
        async.eachLimit(tasks, options.limit, (task, next) => {
            const subprocess = grunt.util.spawn({
                grunt: true,
                args: arrify(task).concat(flags),
                opts: {
                    stdio: [
                        'ignore',
                        'pipe',
                        'pipe'
                    ]
                }
            }, (error, result) => {
                if (!options.logConcurrentOutput) {
                    let output = result.stdout + result.stderr;
                    if (options.indent) {
                        output = indentString(output, 4);
                    }

                    grunt.log.writeln(`\n${output}`);
                }

                next(error);
            });

            if (options.logConcurrentOutput) {
                let subStdout = subprocess.stdout;
                let subStderr = subprocess.stderr;
                if (options.indent) {
                    subStdout = subStdout.pipe(padStream(4));
                    subStderr = subStderr.pipe(padStream(4));
                }

                subStdout.pipe(process.stdout);
                subStderr.pipe(process.stderr);
            }

            subprocesses.push(subprocess);
        }, error => {

//...
            if (options.logConcurrentOutput) {
                let subStdout = subprocess.stdout;
                let subStderr = subprocess.stderr;
                if (options.indent) {
                    subStdout = subStdout.pipe(padStream(4));
                    subStderr = subStderr.pipe(padStream(4));
                }
//line 70
                subStdout.pipe(process.stdout);
                subStderr.pipe(process.stderr);
            }

Will keep poking around but it seems over time my project crashes. not sure exactly where the leak is this is just one lead.

syonfox commented 11 months ago

Ok so I think I fixed this with the fallowing simit added around line 40

if(tasks.length > 10) {
                    let newListenerLimit = tasks.length + 10; // do we need 10 more maybe not but maybe oher things are using the normal 10 limit
                    grunt.log.oklns(
                        'Warning: There are more tasks than your event listener limit. Incresing this to '+ newListenerLimit
                        + "// process.stdout.setMaxListeners(newListenerLimit);"
                    );
                    process.stdout.setMaxListeners(newListenerLimit);
                    process.stderr.setMaxListeners(newListenerLimit);
                }
//just above async.eachLimit(tasks, options.limit, (task, next) => {