-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
process: add process.exitSoon() #6477
Conversation
When set, an internal timer will be set that will exit the process at the given timeout. In the meantime, the registered listeners for process.on('exitingSoon') will be invoked and passed a callback to be called when the handler is ready for the process to exit. The process will exit either when the internal timer fires or all the callbacks are called, whichever comes first. This is an attempt to deal more intelligently with resource cleanup and async op completion on exit (see nodejs#6456).
@@ -70,10 +70,48 @@ function setupConfig(_source) { | |||
|
|||
function setupKillAndExit() { | |||
|
|||
process.exit = function(code) { | |||
const kExitTimer = Symbol('kExitTimer'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tiniest nit: it's probably historic here also, but can we avoid k-prefixed variable names, since const
is common nowadays? See, here.
I like the idea of this though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the little k
. It communicates more than just something not changing; It says “I’m an opaque constant, I’m an identifier for some thingy, and my exact value is irrelevant.”.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright. No strong feelings.
Is this intended to allow code to do cleanup before an exit? If thats the case, it won't solve the problem as the timer can trigger before the cleanup is complete and the process will exit. If you set a really large timer then it may work, but you still must require that all |
-1 A timeout will not guarantee the complete flushing/draining of stdout/stderr. If a timeout is specified then |
I think I'm -1 on this as well. We've seen just in our own CI that timer-based solutions tend to introduce flaky behavior. |
Discoverability of the functionality of Any change to |
Please don't limit every current contribution to |
Yep, there are definitely limitations with this approach. Btw, the intent here is not to say this is the way we should do this, but to give one concrete alternative possibility. (i.e. I'm not sure I'm +1 on this either ;-) ..) |
I think I am -1 on this approach as well for the reasons already given. |
One approach would be shutdown hooks which are allowed to complete before the run-time shuts down. In this case when process.exit() was called, the shutdown hooks would be invoked and once they complete then the exit would complete. This has the advantage that you don't clobber the running of a hook with some arbitrary timeout and you can exit as soon as all the hooks complete. There still is the issue of what happens if a hook causes you to block forever, but that's potentially a different issue. It also means that for existing applications (where no hooks are registered) behavior is the same as today and you don't need to change any of the existing process.exit() calls. I'd favor something based on that approach as opposed to using the timeout as described. |
We get that to an extent already with
If the
|
I can't see how adding more indeterminism to this (or anything else) can possibly help anything. --1 |
@jasnell I like that last proposal of yours, and preferably with running |
It certainly could, yes @addaleax |
does this still apply to the updated proposal " the shortcoming is that any async work gets lost." except that they have the timeout period to complete ? |
@mhdawson ... only if you passed |
I will update this PR with the alternative and will keep iterating until we come to a solution that is workable. |
@jasnell +1 to new function name
@mhdawson Is this shutdown hook a synchronous action without returning to the event loop? Would it be possible to drain any node stream in such a shutdown hook? |
@kzc .. yes, event handlers are invoked sync and since you provide the handler, you'd be able to clean up anything you'd need as part of the flow, including any other streams you need to have drained. |
All, ok, I've pushed a refactored update that uses a separate
The test cases show examples. Nothing specific to draining the stdio streams has been added to this yet but it could be done easily by adding a |
@@ -44,6 +44,32 @@ process.on('exit', (code) => { | |||
console.log('About to exit with code:', code); | |||
}); | |||
``` | |||
## Event: 'exitingSoon' | |||
|
|||
Emitted when `process.exit()` is called using the optional `timeout` argument. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this PR adding an extra argument to process.exit
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry no, in the refactored version this is changed. I just missed a doc edit... fixing now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed! :-)
Will sync shutdown hooks be part of this PR? |
You mean a default hook that ensures stdout/stderr are flushed? It's possible, they're not there yet as I'm trying to do this incrementally to make sure it's heading the right direction |
I suppose the sync shutdown hook @mhdawson described would belong in another PR as it relates specifically to |
@kzc ... how would that be different than the existing |
My suggestion would be to approach this very differently: Make
At the same time, I don't think we should alter Edit: it is possible that this is out of scope for |
(I would suggest opening a new PR for that, if we go that way. But we should not add this.) |
I'm -1 on those changes at all, anything basic is as easily implementable at user-level. Anything non-basic is too specific for the application and task at hand and can't be generally handled from core anyway. That said, I definitely like the fact we're having discussion about resource cleanup. I think it's an area where core should be involved in more - though possibly only through adding more and better documentation about the topic. |
We're not likely to get consensus on changes here following this approach. Closing. |
@jasnell Thanks for exploring this design. It was a useful exercise. Without the event loop what actions you can perform in a shutdown hook are very limited. This is a deceptively difficult problem. I don't know how to solve it other than the way |
@kzc this is not a deceptively difficult problem - proper resource cleanup is a very difficult problem and is widely recognized as such :) |
Yep, my intent here as far as iterating on the design was to start with a design that was the least intrusive to the Node.js internals, purposefully starting with an approach that could be implementable in userland then iterate back from there. In my opinion, we should only have to touch the node internal native code if we can't find a pure javascript solution, and I see very little value in changing how |
oh.. and while folks are looking at this, there's a somewhat related problem that I've been stewing over lately: #831 ... basically, if stdout is a pipe and the other end closes, stdout.write dies and throws because we have no way of detecting that the other end is closed. I started playing around with some ideas around a pure js solution (following my usual iterative approach) but I think a native solution is going to be the best path forward. |
Checklist
Affected core subsystem(s)
process
Description of change
Updated: adds process.exitSoon([code[, timeout]]) and
'exitingSoon'
event to process. Allows exitingSoon handlers to defer exit until they are ready. Timer is optional.When set, an internal timer will be set that will exit the process at the given timeout. In the meantime, the registered listeners for process.on('exitingSoon') will be invoked and passed a callback to be called when the handler is ready for the process to exit. The process will exit either when the internal timer fires or all the callbacks are called, whichever comes first.This is an attempt to deal more intelligently with resource cleanup and async op completion on exit
Docs / test case included
Refs: #6456