open-cli-tools / concurrently

Run commands concurrently. Like `npm run watch-js & npm run watch-less` but better.
https://www.npmjs.com/package/concurrently
MIT License
6.98k stars 227 forks source link

ERR_UNHANDLED_REJECTION with `killOthers` #473

Closed hrishikesh-k closed 4 months ago

hrishikesh-k commented 4 months ago

Hi!

I have a basic setup like:

import concurrently from 'concurrently'
const processes = concurrently([{
  command: 'free --human --seconds 1',
  name: 'Log memory',
}, {
  command: 'sleep 5',
  name: 'Sleep'
}], {
  killOthers: [
    'failure',
    'success'
  ]
})

This works like:

[Log memory]                total        used        free      shared  buff/cache   available
[Log memory] Mem:           7.6Gi       824Mi       5.9Gi       3.0Mi       887Mi       6.5Gi
[Log memory] Swap:          2.0Gi          0B       2.0Gi
[Log memory] 
[Log memory]                total        used        free      shared  buff/cache   available
[Log memory] Mem:           7.6Gi       824Mi       5.9Gi       3.0Mi       887Mi       6.5Gi
[Log memory] Swap:          2.0Gi          0B       2.0Gi
[Log memory] 
[Log memory]                total        used        free      shared  buff/cache   available
[Log memory] Mem:           7.6Gi       827Mi       5.9Gi       3.0Mi       887Mi       6.5Gi
[Log memory] Swap:          2.0Gi          0B       2.0Gi
[Log memory] 
[Log memory]                total        used        free      shared  buff/cache   available
[Log memory] Mem:           7.6Gi       825Mi       5.9Gi       3.0Mi       887Mi       6.5Gi
[Log memory] Swap:          2.0Gi          0B       2.0Gi
[Log memory] 
[Log memory]                total        used        free      shared  buff/cache   available
[Log memory] Mem:           7.6Gi       825Mi       5.9Gi       3.0Mi       887Mi       6.5Gi
[Log memory] Swap:          2.0Gi          0B       2.0Gi
[Log memory] 
[Log memory]                total        used        free      shared  buff/cache   available
[Log memory] Mem:           7.6Gi       825Mi       5.9Gi       3.0Mi       887Mi       6.5Gi
[Log memory] Swap:          2.0Gi          0B       2.0Gi
[Sleep] sleep 5 exited with code 0
--> Sending SIGTERM to other processes..
[Log memory] free --human --seconds 1 exited with code SIGTERM
node:internal/process/promises:289
            triggerUncaughtException(err, true /* fromPromise */);
            ^

[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "[object Array]".] {
  code: 'ERR_UNHANDLED_REJECTION'
}

As you can see, it's working fine for the most part except towards the end. Not sure why it fails with ERR_UNHANDLED_REJECTION.

If I remove killOthers, and manually exit by pressing Ctrl + C, it works without an issue. I also tried the following:

import {spawn} from 'node:child_process'
const freeProcess = spawn('free', [
  '--human',
  '--seconds',
  '1'
])
freeProcess.stdout.on('data', (data) => {
  console.log(data.toString())
})
setTimeout(() => {
  freeProcess.kill('SIGTERM')
}, 5000)

And it exits correctly without any issues. Am I missing something?

I'm on Ubuntu 22.04 running Node.js 20.12.2.

gustavohenke commented 4 months ago

Hey. You need to handle the result, like this:

concurrently([ /* commands */ ], { /* options */ }).result.then(
  () => console.log('exited successfully'),
  () => console.error('exited with error'),
)
hrishikesh-k commented 4 months ago

Thank you for the quick reply! That works! I read that part in the readme, but didn't think that was necessary to do. My assumption was this won't result in an error, but I should have just tried that path out first, sorry for the noise.