open-cli-tools / open-cli-tools/concurrently

concurrently exitcode=0 when it receives SIGINT itself (e.g. on ^C)

Open
#470 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
7.9k
Forks
281
Avg merge
17h 12m
Merged PRs (30d)
1

Description

MacOS and Linux at least.

Sounds like concurrently tool reaction on receiving SIGINT is exiting with code 0 (instead of exiting with e.g. code 130 as the best-practice reaction on Unix processes). This breaks scripts like:

#!/bin/bash
set -e # stop on failed commands
concurrently "one" "two"
echo "still here"

When ^C is pressed in the above script, it still prints "still there", although it should not.

The reason why proper SIGINT handling is important is also described here: https://mywiki.wooledge.org/SignalTrap#When_is_the_signal_handled.3F, section "Special Note On SIGINT and SIGQUIT".

Repro

Console 1:

$ node_modules/.bin/concurrently --version
8.2.2
$ bash -c "node_modules/.bin/concurrently 'exec sleep 1000' 'exec sleep 2000' && echo Exited with exitcode=0"

Console 2:

$ watch -n0.5 'pstree | egrep "sleep" | egrep -v egrep'

CleanShot 2024-04-10 at 17 54 06@2x

Then ^C in console 3:

CleanShot 2024-04-10 at 17 54 33@2x

When ^C is pressed, SIGINT is sent to the entire process group (which is -78069 in this example). I.e. SIGINT is sent to all 4 processes on the screenshot. The bug is that, when concurrently itself receives that SIGINT, it exits with exitcode=0, i.e. it tells the caller that it terminated successfully, although it's not true. According to default unix practices, the process killed by SIGINT should exit with a nonzero exit code (ideally with code=130 which is 128+SIGINT).

We can reproduce the same behavior by not pressing ^C, but by:

  1. Sending SIGINT to concurrently pid itself.
  2. OR - by sending SIGINT to the whole process group, like kill -SIGINT -78069 in the above example.

Interestingly enough, this happens only when receiving SIGINT. On e.g. SIGTERM or SIGHUP it behaves properly.

P.S.
There is an ugly work-around for this:

bash -c 'node_modules/.bin/concurrently "exec sleep 1000" "exec sleep 2000" & wait $! && echo Exited with exitcode=0'

Since the shell itself also receives that ^C SIGINT (it's a member of the process group), it fails in wait call, so the message is not printed. But again, this is not a good practice (it is based on a side effect, e.g. it still doesn't help when there is no ^C involved, and only concurrently tool is sent with a SIGINT).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the concurrently CLI entry point invoked through node_modules/.bin/concurrently, then reproduce the SIGINT cases in the issue using the provided bash commands. Done means SIGINT causes concurrently to return a nonzero status, ideally 130, so the surrounding script does not print its success message.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
cli, operating-systems
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.