-
Notifications
You must be signed in to change notification settings - Fork 146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
child process workers now attempt to terminate themselves via message #197
Conversation
wow, that is more complicated than I had expected. Thanks for working out this fix, looks good to me! I'm not sure how I could verify whether the fix works in practice but I trust you in that. I'll merge right after you've fixed the accidental |
This causes workers run via `child_process.fork()` to respond to a special message by exiting. On Windows especially, a subprocess killed via `SIGINT` cannot "clean up" after itself, and must exit immediately. This has many implications, but importantly, it can cause `nyc` to fail to report code coverage on worker scripts. A workaround is to listen for a "terminate" message from the parent, perform cleanup (if necessary), and call `process.exit()` itself. `nyc` will then be successful in determining the coverage. Since a child process worker may be very busy (e.g., in an infinite loop) and unable to _handle_ a message from its parent, `workerpool` now has a hardcoded timeout of `1000` ms; if the child does not shut down cleanly within this window, `workerpool` will ask the OS to signal a shutdown via `process.kill()` (which was the old behavior). Short of adding `nyc` and asserting it calculates coverage, the current test suite does a reasonable job of avoiding regressions here.
42d488d
to
c76b530
Compare
I've removed the |
Let me run another test to double-check; I'll paste some screenshots |
I have a minimal reproduction repo which I'm using to test the interaction between In my test repo, I have this test: // test/foo-workerpool.spec.js
const workerpool = require("workerpool");
const assert = require("assert");
(async function () {
const pool = workerpool.pool(require.resolve("../src/foo-workerpool"), {
workerType: "process",
});
const result = await pool.exec("foo");
assert.strictEqual(result, "foo");
console.error("done");
return pool.terminate();
})(); and the source of the worker script: // src/foo-workerpool.js
const workerpool = require("workerpool");
workerpool.worker({
foo() {
console.error('returning "foo"')
return "foo";
},
}); When running the test against Now, trying again with my changes installed from my working copy: Anyway, I think this is ready for your review again. |
I think it may be helpful to add something that notifies the process has been forcibly shut down. a consumer may or may not care, but in my case, it could cause flaky coverage reporting... and/or a configurable timeout |
Thanks Christopher, I'm really glad you where able to track down this tricky issue 👍
That is a good idea! Maybe we can do that behind a I'll now merge and publish your fix. And sorry for the delay. |
I created an issue in order not to forget about your idea: #201 |
Fix is published now in |
This causes workers run via
child_process.fork()
to respond to a special message by exiting.On Windows especially, a subprocess killed via
SIGINT
cannot "clean up" after itself, and must exit immediately. This has many implications, but importantly, it can causenyc
to fail to report code coverage on worker scripts. A workaround is to listen for a "terminate" message from the parent, perform cleanup (if necessary), and callprocess.exit()
itself.nyc
will then be successful in determining the coverage.Since a child process worker may be very busy (e.g., in an infinite loop) and unable to handle a message from its parent,
workerpool
now has a hardcoded timeout of1000
ms; if the child does not shut down cleanly within this window,workerpool
will ask the OS to signal a shutdown viaprocess.kill()
(which was the old behavior).Short of adding
nyc
and asserting it calculates coverage, the current test suite does a reasonable job of avoiding regressions here.notes:
I've found that the undesirable behavior (failure to collect coverage from a forked process) only sometimes occurs on macOS (probably system-state-dependent), but it almost always occurs on Windows. Spawned processes do not seem to exhibit this behavior, but that is not helpful for
workerpool
.Ref: mochajs/mocha#4372, istanbuljs/nyc#762