Skip to content

Exits with code 1 on SIGTERM without waiting for child #4667

@adamdunkley

Description

@adamdunkley

Do you want to request a feature or report a bug?
This is a bug

What is the current behavior?
Currently yarn terminates with exit code 1 when it receives a SIGTERM without waiting for the child to exit and without passing its child's exit status up the chain.

The issue that this stemmed from was about handling SIGTERM events (#3424) and was introduced in pull request #3789.

If the current behavior is a bug, please provide the steps to reproduce.

Create a simple express script:

const app = require('./express');

const server = app.listen(config.port, () => {
    console.log(`server started`);
});
process.on('SIGTERM', () => {
    server.close(() => {
      setTimeout(() => {
        process.exit(0);
      }, 1000);
    });
});

Note that the script uses setTimeout to wait before exiting (as if it is waiting 1s for a client connection to end).

⇒  yarn start
yarn run v1.1.0
$ node src/index.js
server started

In another session run the following with the PID of that command:

kill $PID

Finally in that first session after it has exited:

⇒  echo $?
1

You can see that it exits immediately (not waiting 1s) and the error code is 1.

What is the expected behavior?

Expected behaviour is to do exactly as node would:

⇒  node src/index.js
server started
⇒  echo $?
0

This waits the 1s for the setTimeout (we kill using kill $PID in between the node and echo commands as above). You can also see we get the child's exit status (you can verify this by setting it to something else like process.exit(9) and seeing it come out).

I see some comments in the code where it is questioning what we should do about this:

// We want to exit immediately here since `SIGTERM` means that
// If we lose stdout messages due to abrupt exit, shoot the messenger?
process.exit(1); // eslint-disable-line no-process-exit

I think it's the child's job to decide what to do if a SIGTERM event is received. The parent should hand the signal to the child and wait to see if it exits. The only thing that I think Yarn should consider is whether there is a time limit that we would like to wait for naughty child processes that do not exit on time. Docker sets this to 10 seconds, whatever we set this to (if we do at all!!) we should make it a) clear and b) configurable.

One other thing: currently not sure what we do with SIGINT. I see weird stuff happening with that too (and I presume other signals?). Probably worth investigating signal handling more holistically?

Please mention your node.js, yarn and operating system version.

  • Node version: 7 & 8
  • Yarn version: 1.10.0
  • macOS 16.3.0 and alpine

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions