Uh oh!
There was an error while loading. Please reload this page.
Add check for h2.connection.ConnectionState.CLOSED in AsyncHTTP2Connection.is_available - #679
Conversation
…nnection.is_available`
zanieb
commented
May 5, 2023
You can see how this changes things in my reproduction at https://github.com/madkinsz/httpcore-h2-closed Without this change, when the NGINX proxy is reset a With this change, the first error is raised but subsequent requests succeed. |
lovelydinosaur
commented
May 9, 2023
Looks like a good start, thanks! 💛
Hrm, yes it's not immediately obvious what the most graceful approach is here but let's start at the start. It might(?) be worth rounding out this PR a bit with a test case in:
(I can help out if needed.) A test there wouldn't really be sufficient because all we can demonstrate at that level is "if we send these frames, then the connection interface will behave like X", but it'd be something. |
zanieb
commented
May 9, 2023
Thanks for the response Tom! I'll take a swing at the test and ping you when it's added or if I run into any problems. |
zanieb
commented
May 9, 2023
We can add a test like deftest_http2_connection_closed_unexpectedly():
origin=Origin(b"https", b"example.com", 443)
stream=MockStream(
[
hyperframe.frame.SettingsFrame().serialize(),
]
)
withHTTP2Connection(origin=origin, stream=stream, keepalive_expiry=5.0) asconn:
conn._h2_state.close_connection()
withpytest.raises(ProtocolError):
conn.request("GET", "https://example.com/")
assertnotconn.is_available()If you want to add something that doesn't reach into the underlying |
lovelydinosaur
commented
May 10, 2023
Maybe a test where the server sends one response and then sends a |
zanieb
commented
May 10, 2023
@tomchristie yep that works to reproduce the issue, added in 00f98c5 |
lovelydinosaur
commented
May 11, 2023
Looking good! I verified locally that without the implementation change, the test fails with the connection stuck in an We can improve on this further by ensuring that requests after a GOAWAY frame get a * Ideally we'd also allow existing streams to complete after a GOAWAY frame, so long as they are |
zanieb
commented
May 11, 2023
Great that makes sense to me! Let's merge this and I'll open a follow up that raises the Unfortunate that there's no traction in that |
Addresses encode/httpx#2112 and PrefectHQ/prefect#7442
The issue here is that the underlying h2 connection can reached a CLOSED state without the httpcore connection being marked as CLOSED. This causes subsequent requests to continue to reuse the closed connection but they will always fail with a protocol error. By adding a check to
is_available, we'll avoid using this bad connection after the first request fails.It seems likely that we could check the h2 connection state somewhere else as well i.e. before handling every request. I'd appreciate some guidance from other maintainers.
Ideally we'd avoid sending any events when there's a closed connection which would avoid the
LocalProtocolErrorin the first place, but first let's avoid holding closed connections in the pool.