-
-
Notifications
You must be signed in to change notification settings - Fork 168
Close inactive connections and requests #425
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
Close inactive connections and requests #425
Conversation
mmoreram
commented
Nov 9, 2021
@WyriHaximus is there any chance you can merge this PR? Seems to be tested, and increases so much the memory performance :)
7b3f5b6 to
0ddb503
Compare
WyriHaximus
commented
Nov 10, 2021
@WyriHaximus Thanks for the update!
Can you provide a quick update here, what's your plan for this feature with regards to #425? We've briefly discussed (off channel) that this should eventually send a
408 Request Timeoutresponse for the initial connection but not for keep-alive connections that send no following request. I agree breaking this up into smaller PRs can be useful, but it looks like this might also work in a single PR, so I'll leave this up to you. Let me know if there's anything I can help with and/or if you want me to take over from here +1
@clue Right, been thinking about this, and doesn't it make sense to do this with all requests in flight, instead of only on the first?
0ddb503 to
4af0447
Compare
WyriHaximus
commented
Nov 10, 2021
@WyriHaximus is there any chance you can merge this PR? Seems to be tested, and increases so much the memory performance :)
@mmoreram There are a few details we need to polish before this PR is done and it can be merged. Like the 408 responses for when an inflight request times out. And ensuring we don't cut off websocket connections with this.
4af0447 to
8d4d62c
Compare
WyriHaximus
commented
Nov 10, 2021
@WyriHaximus Thanks for the update!
Can you provide a quick update here, what's your plan for this feature with regards to #425? We've briefly discussed (off channel) that this should eventually send a408 Request Timeoutresponse for the initial connection but not for keep-alive connections that send no following request. I agree breaking this up into smaller PRs can be useful, but it looks like this might also work in a single PR, so I'll leave this up to you. Let me know if there's anything I can help with and/or if you want me to take over from here +1@clue Right, been thinking about this, and doesn't it make sense to do this with all requests in flight, instead of only on the first?
Just made this change, the code is cleaner as well. I Will check the relevant RFC's later today, but until that my position is that any request in a keep alive connection can timeout for any number of reasons.
src/Io/StreamingServer.php
Outdated
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.
Makes me wonder if we should expose the RequestHeaderParser instead, given we only use the timeout value to pass it forward. (Refs #359)
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.
As in also make it possible to inject a different header parser? We could do that so we can have a C based extension for parser to speed it up?
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.
KISS: The StreamingServer is marked @internal, as is the RequestHeaderParser. This means we can easily inject the RequestHeaderParser to the StreamingServer inside the Server class. Constructor may have to be changed, but doesn't affect BC, because the public Server interface is not affected (at least not as part of this change).
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.
Yes, I'm fully aware, I'm also thinking ahead. But maybe, if we want to go there, we should ship that C based extension to speed it up
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'm not sure this is currently our hot path, but if we have evidence an optional extension will speed things up, I'm all for it 👍 I think we're on the same page here and should probably leave this up for a follow-up PR?
In either case I think your changes are a welcome improvement as is and injecting the RequestHeaderParser into the StreamingServer can help simplify the dependency injection both now and longer-term 👍
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'm not sure this is currently our hot path, but if we have evidence an optional extension will speed things up, I'm all for it 👍 I think we're on the same page here and should probably leave this up for a follow-up PR?
Of course, that would be a follow-up PR. And we have tons of other things to do.
In either case I think your changes are a welcome improvement as is and injecting the
RequestHeaderParserinto theStreamingServercan help simplify the dependency injection both now and longer-term 👍
Sounds good! 🚢 🇮🇹 !
(Will fix that thing below this 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.
It's my understanding the HttpServer should be simplified to call something like new StreamingServer($middleware, new RequestHeaderParser($loop, $idleConnectionTimeout)).
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.
It took some work, but I think it's worth the refactoring ❤️
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.
Took some working on this, but ended up with new StreamingServer($middleware, $idleConnectionTimeout) because the connection/requests timing out is handled in the StreamingServer.
clue
commented
Feb 5, 2022
@WyriHaximus Thanks for the update!
Can you provide a quick update here, what's your plan for this feature with regards to #425? We've briefly discussed (off channel) that this should eventually send a408 Request Timeoutresponse for the initial connection but not for keep-alive connections that send no following request. I agree breaking this up into smaller PRs can be useful, but it looks like this might also work in a single PR, so I'll leave this up to you. Let me know if there's anything I can help with and/or if you want me to take over from here +1@clue Right, been thinking about this, and doesn't it make sense to do this with all requests in flight, instead of only on the first?
Just made this change, the code is cleaner as well. I Will check the relevant RFC's later today, but until that my position is that any request in a keep alive connection can timeout for any number of reasons.
Did take a look at the relevant RFCs (https://datatracker.ietf.org/doc/html/rfc7230#section-6 and https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.7 come to mind) and it looks like this is indeed under-specified behavior. MDN mentions "Note: some servers merely shut down the connection without sending this message." (https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) and this actually seems to match my observations.
-
If you open a connection github.com:80 or google.com:80 and don't send a complete request, the connection will be closed with no message after a timeout. Same if you send a request using keep-alive and then wait for the timeout. Same if you send a request using keep-alive and then send an incomplete request header.
-
If you open a connection to Apache and don't send any data, the connection will be closed with no message after a timeout. If you open a connection and send an incomplete request header, the connection will be closed with a message after a timeout. In either case, a 408 will be logged. If you send a request using keep-alive and then wait for the timeout, the connection will be closed with no message after a timeout and no log message. If you send a request using keep-alive and then send an incomplete request header, the connection will be closed with an message after a timeout and a log message.
-
If you open a connection to nginx, it will close the connection with no message after after a timeout in either case. Even though I'm using default settings (http://nginx.org/en/docs/http/ngx_http_core_module.html#client_header_timeout), I've never seen an 408 response in my tests.
-
Note there's also https://www.haproxy.com/blog/haproxy-and-http-errors-408-in-chrome/ which suggests sending a 408 used to be(?) a problem in chrome to its inherent race condition. See also https://stackoverflow.com/questions/42631273/how-do-browsers-handle-http-keepalive-race-condition for some background.
Neither behavior appears to be against specs, so I wonder what behavior we should use here.
2684f7d to
ec39c37
Compare
WyriHaximus
commented
Mar 23, 2022
Neither behavior appears to be against specs, so I wonder what behavior we should use here.
@clue For now, merge this as is and I'll do a follow up PR to make the behavior configurable.
src/Io/StreamingServer.php
Outdated
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.
It's my understanding the HttpServer should be simplified to call something like new StreamingServer($middleware, new RequestHeaderParser($loop, $idleConnectionTimeout)).
3db8005 to
4c481fa
Compare
1de8cd4 to
4f47478
Compare
efc3762 to
7407d82
Compare
7407d82 to
3398ca8
Compare
3398ca8 to
25f7136
Compare
655ca5e to
56057dc
Compare
56057dc to
d0a0442
Compare
e447b34 to
6b78aa5
Compare
6b78aa5 to
6491fab
Compare
This new middleware introduces a timeout of closing inactive connections between requests after a configured amount of seconds. This builds on top of reactphp#405 and partially on reactphp#422
6491fab to
a270175
Compare
Uh oh!
There was an error while loading. Please reload this page.
This builds on top of #405 and further builds out #423 by also
close connections with inactive requests.
Closes: #423