-
Notifications
You must be signed in to change notification settings - Fork 16
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
A better way to detect a process is exiting #42
Comments
I know this is a can of worms but the ability to have an async exit handler would be fantastic. Currently it is only possible to run synchronous functions in the exit handler (IE I understand that allowing the event loop to resume could allow excessive deferment of the exit but this is already the case, IE |
This is sorely needed. There are many use-cases that requires running code right before exit:
I built |
A little more specific info about what is wanted would be helpful here, but I'll take a guess at one thing, which is allowing async code like the below:
Note that in the case of node doing a "normal" exit because the loop is empty, this already possible. There is https://nodejs.org/api/process.html#process_event_beforeexit, and it does allow async code to be scheduled on exit, and after that when the loop is empty again, node will attempt to exit again (after emitting beforeExit again, which might wake it up... etc.). |
An additional use case for it would be to clean up CLI spinners or progress bars. |
For nyc or a test runner to use async exit handlers I think it would be expected that pending asyncness initialized before A more generic solution might be if we could start a |
Hello! Thank you for looking into this. I agree with the needs and I think I mostly said what I wanted to say in this issue. Reading it now, I think the originally issue unnecessarily coupled it with async functions/promise cancellation, etc, which is not really needed to illustrate the core issue. From my perspective, the single handler APIs are only viable if you are writing an application. It could be nicer, and handle more edge cases, but if you have full control about the desired behavior on the final "app" (executable/script), you can probably make it work enough. However, if you are a library/middleware/plugin designed to be "pulled in" to an app, there is nothing that really works IMO. Some challenges are:
IMO, these two are the core unsolvable constraints with the current APIs. I don't think it is a fundamental limitation to how the event loop works, how signals are delivered etc, but someone need to be the "coordinator" here, because again, you can actually build this behavior if you control everything end-to-end. I just think that should be the Node runtime (or the standard library at least). |
I've found a way to eliminate use of the |
Good idea to leave async out of it for now. I don't want to edit the subject without permission, but @bcoe I suggest you change "exiting" to "terminating". Processes terminate on Unix because they exited, or because they were signalled, and the exit case is already handled well enough (I think), its a handler for the signal paths that are being asked for (also, I think). I'm not as familiar with Windows, but there are no signals, so that distinction doesn't exist, but IIRC there is a If the requirements could enumerate either in words or js code the conditions that should be trapped and forwarded to a termination handler, that would be handy. For example, I can read https://github.com/sindresorhus/exit-hook/blob/master/index.js#L18, but since @sindresorhus said it does not meet requirements, its not quite the requirements! :-) Note that https://github.com/sindresorhus/exit-hook/blob/b504031173d8e2c2ce6bb9f0b6557cbe6dedecd5/index.js#L18 should be And just to set the bar for tooling that would be using this... it is literally impossible on Unix, from within a process, to hook all causes of process termination, SIGKILL in particular is impossible to trap, and SIGSEGV is unwise to (if node even allows it), so if tooling layers need to be robust to all cases of termination, they need to be aware of this. But probably coverage checkers don't need to account for processes that were SIGKILLed or that seg faulted! |
^ next steps |
If a signal which results in termination can safely be hooked then I want it to execute my terminate hook. signal-exit does capture a larger list of signals (https://github.com/tapjs/signal-exit/blob/master/signals.js) compared to exit-hook, these do not include the signals which are impossible to hook or documented by node.js as unsafe to hook. I would not object to removal of SIGABRT from the list of reasons. From signal-exit README:
I would add DEP0018 unhandled promise rejections to this list of reasons once that results in process termination with a normal error, but probably not when For nyc one key detail of An alternative would be to support a two-pass execution of process.on('terminate', () => {
process.on('terminate', () => {
// run after all terminate handlers that were added before exit
});
}); Instead of function terminateHookPass() {
const hooks = process.listeners('terminate');
process.removeAllListeners('terminate');
for (const hook in hooks) {
hook.apply(process)
}
}
let dispatchTerminateDone = false;
function dispatchTerminateHooks() {
if (dispatchTerminateDone) {
return;
}
// Ignore hooks added during the second pass even
// if dispatchTerminateHooks is called again.
// Not sure this will actually be needed
dispatchTerminateDone = true;
// Execute hooks added during operation
terminateHookPass();
// Execute hooks added during the first pass (`alwaysLast` hooks)
terminateHookPass();
process.removeAllListeners('terminate');
} An alternative would be a I have not yet given thought to what information should be passed to the |
Some Background
Part of the motivation of building
NODE_V8_COVERAGE
into core, was that it made it significantly easier to capture exit behavior.Prior to this, tools like nyc used error-prone hacks like, signal-exit to detect process termination.
Proposal
It would be nice to have an API hook that fires when Node.js is about to terminate, regardless of whether it's:
related conversations: nodejs/node#29480, nodejs/node#28960
Just wanted to kick off this conversation (@sindresorhus actually brought it up initially), CC: @coreyfarrell, @isaacs.
The text was updated successfully, but these errors were encountered: