-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
stream: destroy(err)
predictability
#31060
Comments
I would like to request guidance from the TSC in regards to how to resolve this and if any of the proposed solutions are satisfactory. |
While I'm hesitant to speak for the TSC as a whole, I'd expect the TSC to prefer invested collaborators discuss the issue and try to reach consensus on how to handle this. @nodejs/streams |
(Forgot to include that the @nodejs/tsc would hopefully get involved if there is an impasse.) |
There is a typo in example 3. |
This comment has been minimized.
This comment has been minimized.
Agree with @Trott here. Its the streams experts who should weigh in. I'm a user, not an expert, but I see nothing surprising about Destroys aren't some kind of "queued event" wherein they all get queued up, then processed in order, and results seen in order. Its an orthogonal control flow (hopefully rare) -- orthogonal to the normal stream duplex ordered data followed by a FIN/end flow. They don't have well defined interplay, because in theory once .destroy() is called, the data flow no longer matters, other than it will terminate sometime before the destroy completes. To have two destroy flows initiated is just a race condition.... exactly how they interact cannot be deterministic, other than that only the first one should win, and the second should do no harm. Of course... if some popular package out there breaks when |
What I believe is the main objection against this can be found here #29197 (comment)
|
As written in #29197 it breaks |
For anyone who didn't click through, here's the comment:
|
Note that I’m also ok in leaving things as-is. |
Another example of where this is relevant: #31054 (comment) |
The more I think about it the more I would prefer 1. Would resolve a lot of (for me) weird edge cases I keep running into. Though again I don't know how much it would break the ecosystem (other than |
Ok, then I think it makes sense to restore #29197 to its original state, rebase against master and check CITGM event though results may be misleading because current behavior may not be tested (for example it isn't in |
An update on solution 1, #29197 (comment) |
The current official API for destroying is
destroy(err)
. Where the user can supply a custom destroyer on the prototype through_destroy(err, cb)
and whereerr
comes from the call todestroy(err)
. The user can choose to ignore, replace, forward or modifyerr
through the callback.However, what is the actual vs expected behavior of this in regards to multiple calls to
destroy(err)
? The_destroy
destroyer can only be invoked during the first call and any further calls todestroy(err)
will currently bypass this and directly emit'error'
.Examples
Example 1: We want to swallow errors. However, a second call to
destroy(err)
will actually emit an error.Example 2: We want to (in some manner) modify the error.
Example 3: When the destroyer has fully completed and the stream is effectivly destructed an error can unexpectedly be injected.
This would fail even with #29197 where errors are swallowed after
'close'
.Solutions
Originally in stream: fix multiple
destroy()
calls #29197 we discussed that only the first call todestroy(err)
is applied and any further calls are noop. This might be logical since we can only call_destroy
once to apply any related logic. This would resolve the issues in all the examples above. The downside of this is in casedestroy(err)
is called afterdestroy()
while destruction is still on-going, in which case the error would be swallowed. Due to this objection we came to the compromise of "don't emit'error'
after'close'
" to resolve the specific issue that PR was trying to resolve (i.e. when can no further'error'
events be emitted).The first error always wins stream: first error wins and cannot be overriden #30982. Which would partly resolve Example 3 but not allow other error handling through
_destroy
.Just leave things as they are and possibly document the edge cases.
Refs
destroy()
calls #29197)_destroy
can swallow error? (custom_destroy
can swallow error? #30979)The text was updated successfully, but these errors were encountered: