-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
http: add support for abortsignal to http.request #36048
Conversation
Review requested:
|
aa6a902
to
bb957b5
Compare
const server = http.createServer(common.mustNotCall((req, res) => { | ||
})); |
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.
const server = http.createServer(common.mustNotCall((req, res) => { | |
})); | |
const server = http.createServer(common.mustNotCall()); |
doc/api/http.md
Outdated
@@ -2596,6 +2601,10 @@ events will be emitted in the following order: | |||
Setting the `timeout` option or using the `setTimeout()` function will | |||
not abort the request or do anything besides add a `'timeout'` event. | |||
|
|||
Passing an `AbortSignal` and then calling `abort` on the corrosponding |
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.
Passing an `AbortSignal` and then calling `abort` on the corrosponding | |
Passing an `AbortSignal` and then calling `abort` on the corresponding |
lib/_http_client.js
Outdated
if (options.signal) { | ||
validateAbortSignal(options.signal, 'options.signal'); | ||
const listener = (e) => this.destroy(); | ||
options.signal.addEventListener('abort', listener); |
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.
Nit: perhaps use once here as well ({ once: true })?
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 feel like it would be more hacky since we're removing the listener below even if it is invoked since close
should be fired.
If I pass once
and someone aborts
s the controller - the signal will fire abort
, the listener will be removed, then close
will fire and we will try removing a non-existing listener which will technically be no harm but will be slightly confusing.
doc/api/http.md
Outdated
@@ -2336,6 +2336,9 @@ This can be overridden for servers and client requests by passing the | |||
<!-- YAML | |||
added: v0.3.6 | |||
changes: | |||
- version: REPLACEME | |||
pr-url: https://github.com/nodejs/node/pull/319999 |
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.
pr-url: https://github.com/nodejs/node/pull/319999 | |
pr-url: https://github.com/nodejs/node/pull/36048 |
|
||
|
||
{ | ||
// destroy with AbortSignal |
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.
// destroy with AbortSignal | |
// Destroy with AbortSignal |
bb957b5
to
728d4ad
Compare
doc/api/http.md
Outdated
@@ -2596,6 +2601,10 @@ events will be emitted in the following order: | |||
Setting the `timeout` option or using the `setTimeout()` function will | |||
not abort the request or do anything besides add a `'timeout'` event. | |||
|
|||
Passing an `AbortSignal` and then calling `abort` on the corresponding | |||
`AbortConttoller` will behave the same way as calling `.destroy()` on the |
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.
`AbortConttoller` will behave the same way as calling `.destroy()` on the | |
`AbortController` will behave the same way as calling `.destroy()` on the |
lib/_http_client.js
Outdated
@@ -169,6 +172,14 @@ function ClientRequest(input, options, cb) { | |||
if (options.timeout !== undefined) | |||
this.timeout = getTimerDuration(options.timeout, 'timeout'); | |||
|
|||
if (options.signal) { |
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.
Should we extract the value in a variable to be safe? Options could be changed later or the property could be a getter that throws afterwards
728d4ad
to
89c38be
Compare
lib/_http_client.js
Outdated
const signal = options.signal; | ||
if (signal) { | ||
validateAbortSignal(signal, 'options.signal'); | ||
const listener = (e) => this.destroy(); |
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 would call .destroy()
with an error.
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... think you're right. If cancellation is abnormal elsewhere it should likely be abnormal termination here and abort with an AbortError with a .code
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... think I changed my mind again. Lol, I think calling .destroy
without an error is probably right and the error the user is getting should probably be ECONNRESET
and not an AbortError
anyway.
I'd rather users get consistent errors on request aborts than always getting AbortError
s consistent errors when using AbortController.
I'm really not sure here tbh.
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.
cc @ronag
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 don't think it will ECONNRESET if aborted before a socket is assigned.
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.
@ronag it does (there is a test for it)
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.
cc @jasnell
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.
This is a bit weird to me... if we are going to do this isn't it better to just add signal support generically to streams?
I don't really see the point of this since streams have .destroy()
.
@ronag even if http.request returns a stream and we make those cancelable with signals, it should still take a signal as a parameter for ownership. If we make Allowing users to destroy an |
I don't quite see if but don't have a strong opinion. However, I do think if we do this we should do it on the streams level. |
I will follow up with a PR for readable Edit: very much wip @ronag https://github.com/nodejs/node/compare/master...benjamingr:abort-signal-stream?expand=1 will make a PR sometime this week hopefully |
Why not have this PR also destroy with |
@ronag I think users would probably expect an ECONNRESET - no? |
Not necessarily. What about the case when aborting before I don't have a strong opinion. |
@ronag the test here aborts synchronously, that is before socket iiuc. Note I am not sure what's the right thing either - and also in http2, I don't understand the implications of why aborting with an error here would matter so if there is a good reason to My involvement in the project and willingness to do the work does not excuse my ignorance in this case. So if I'm missing something please let me know. (The more general AbortSignal for Readable will |
Landed in a46b21f...2097ffd |
PR-URL: #36048 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Denys Otrishko <[email protected]> Reviewed-By: Ricky Zhou <[email protected]> Reviewed-By: Rich Trott <[email protected]>
- Builds on nodejs#36048 and nodejs#36084 - Modify test to verify this fact
PR-URL: #36048 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Denys Otrishko <[email protected]> Reviewed-By: Ricky Zhou <[email protected]> Reviewed-By: Rich Trott <[email protected]>
Notable changes: dns: * (SEMVER-MINOR) add a cancel() method to the promise Resolver (Szymon Marczak) #33099 events: * (SEMVER-MINOR) add max listener warning for EventTarget (James M Snell) #36001 http: * (SEMVER-MINOR) add support for abortsignal to http.request (Benjamin Gruenbaum) #36048 http2: * (SEMVER-MINOR) allow setting the local window size of a session (Yongsheng Zhang) #35978 lib: * (SEMVER-MINOR) add throws option to fs.f/l/statSync (Andrew Casey) #33716 path: * (SEMVER-MINOR) add `path/posix` and `path/win32` alias modules (ExE Boss) #34962 readline: * (SEMVER-MINOR) add getPrompt to get the current prompt (Mattias Runge-Broberg) #33675 src: * (SEMVER-MINOR) add loop idle time in diagnostic report (Gireesh Punathil) #35940 util: * (SEMVER-MINOR) add `util/types` alias module (ExE Boss) #34055 PR-URL: TODO
Notable changes: dns: * (SEMVER-MINOR) add a cancel() method to the promise Resolver (Szymon Marczak) #33099 events: * (SEMVER-MINOR) add max listener warning for EventTarget (James M Snell) #36001 http: * (SEMVER-MINOR) add support for abortsignal to http.request (Benjamin Gruenbaum) #36048 http2: * (SEMVER-MINOR) allow setting the local window size of a session (Yongsheng Zhang) #35978 lib: * (SEMVER-MINOR) add throws option to fs.f/l/statSync (Andrew Casey) #33716 path: * (SEMVER-MINOR) add `path/posix` and `path/win32` alias modules (ExE Boss) #34962 readline: * (SEMVER-MINOR) add getPrompt to get the current prompt (Mattias Runge-Broberg) #33675 src: * (SEMVER-MINOR) add loop idle time in diagnostic report (Gireesh Punathil) #35940 util: * (SEMVER-MINOR) add `util/types` alias module (ExE Boss) #34055 PR-URL: TODO
Notable changes: dns: * (SEMVER-MINOR) add a cancel() method to the promise Resolver (Szymon Marczak) #33099 events: * (SEMVER-MINOR) add max listener warning for EventTarget (James M Snell) #36001 http: * (SEMVER-MINOR) add support for abortsignal to http.request (Benjamin Gruenbaum) #36048 http2: * (SEMVER-MINOR) allow setting the local window size of a session (Yongsheng Zhang) #35978 lib: * (SEMVER-MINOR) add throws option to fs.f/l/statSync (Andrew Casey) #33716 path: * (SEMVER-MINOR) add `path/posix` and `path/win32` alias modules (ExE Boss) #34962 readline: * (SEMVER-MINOR) add getPrompt to get the current prompt (Mattias Runge-Broberg) #33675 src: * (SEMVER-MINOR) add loop idle time in diagnostic report (Gireesh Punathil) #35940 util: * (SEMVER-MINOR) add `util/types` alias module (ExE Boss) #34055 PR-URL: #36232
Notable changes: dns: * (SEMVER-MINOR) add a cancel() method to the promise Resolver (Szymon Marczak) #33099 events: * (SEMVER-MINOR) add max listener warning for EventTarget (James M Snell) #36001 http: * (SEMVER-MINOR) add support for abortsignal to http.request (Benjamin Gruenbaum) #36048 http2: * (SEMVER-MINOR) allow setting the local window size of a session (Yongsheng Zhang) #35978 lib: * (SEMVER-MINOR) add throws option to fs.f/l/statSync (Andrew Casey) #33716 path: * (SEMVER-MINOR) add `path/posix` and `path/win32` alias modules (ExE Boss) #34962 readline: * (SEMVER-MINOR) add getPrompt to get the current prompt (Mattias Runge-Broberg) #33675 src: * (SEMVER-MINOR) add loop idle time in diagnostic report (Gireesh Punathil) #35940 util: * (SEMVER-MINOR) add `util/types` alias module (ExE Boss) #34055 PR-URL: #36232
PR-URL: nodejs#36048 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Denys Otrishko <[email protected]> Reviewed-By: Ricky Zhou <[email protected]> Reviewed-By: Rich Trott <[email protected]>
PR-URL: nodejs#36048 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Denys Otrishko <[email protected]> Reviewed-By: Ricky Zhou <[email protected]> Reviewed-By: Rich Trott <[email protected]>
PR-URL: nodejs#36048 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Denys Otrishko <[email protected]> Reviewed-By: Ricky Zhou <[email protected]> Reviewed-By: Rich Trott <[email protected]>
PR-URL: #36048 Backport-PR-URL: #38386 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Denys Otrishko <[email protected]> Reviewed-By: Ricky Zhou <[email protected]> Reviewed-By: Rich Trott <[email protected]>
cc @mcollina @jasnell @addaleax
This is the last one from #35877 (comment) - if you have any more APIs you want me to add support for AbortSignal in before I go back to that list I started making back then please let me know :]
Also we should talk about streams and this probably.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes