Skip to content

Remove shielding from cancellation process. - #927

Draft
lovelydinosaur wants to merge 4 commits into
masterfrom
remove-shielding-from-cancellation-process
Draft

Remove shielding from cancellation process.#927
lovelydinosaur wants to merge 4 commits into
masterfrom
remove-shielding-from-cancellation-process

Conversation

@lovelydinosaur

Copy link
Copy Markdown
Contributor

For handling async-cancellations we're currently shielding close operations, in order to ensure we don't end up with a connection in an inconsistent state when cancellations are used.

A better approach is to ensure that the state changes for this case are handled synchronously (so that cancellations won't propagate into those). While the network close remains unshielded async (it's okay for cancellations to propagate into those).

Reasoning about the state when cancellations occur is a bit fiddly, tho I think we can apply this same style of approach all the way through to remove the need for async cancellation-shielding. (Closing state is applied first synchronously. Network close operations are then attempted, and may propagate cancellation.)

Refs #922

Comment on lines +361 to +364
async with Trace("response_closed", logger, self._request, kwargs={}):
if not self._closed:
self._closed = True
if self._connection._connection_should_close():

@MarkusSintonenMarkusSintonenJun 13, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the await inside the Trace.__aenter__ cause issues here? Ie can there be a cancellation with the await inside it that would cause a skip of the self._closed-checks and self._connection._connection_should_close()? (Might be a stupid question so sorry about that :D)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this is a problem, It's also a problem if the trace function raises, I think you'll need to do this:

# synchronization.pyaclose_forcefully=anyio.aclose_forcefullydefclose_forcefully(sock):
sock.close()
asyncdefaclose(self):
entered_cmgr=Falsetry:
asyncwithTrace("response_closed", logger, self._request, kwargs={}):
entered_cmgr=Trueifnotself._closed:
self._closed=Trueifself._connection._connection_should_close():
awaitself._connection.aclose()
exceptBaseException:
ifentered_cmgr:
raiseifnotself._closed:
self._closed=Trueifself._connection._connection_should_close():
awaitaclose_forcefully(self._connection)
raise

@T-256T-256 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are also in connection_pool and http2

Comment on lines +263 to +266
return False

self._state = HTTPConnectionState.CLOSED
return True

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why returning bool here? all references are trying to close connection, why avoid do it at here?

Comment threadhttpcore/.DS_Store

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

junk?

@rattrayalex

Copy link
Copy Markdown

@tomchristie do you intend to take this over the line, or would it be helpful for someone else to try to take it over?

(for context, users of openai-python are reporting unusably slow performance, which seems related to https://github.com/encode/httpx/issues/3215)

Comment threadhttpcore/.DS_Store

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably don't want this file

Comment on lines +361 to +364
async with Trace("response_closed", logger, self._request, kwargs={}):
if not self._closed:
self._closed = True
if self._connection._connection_should_close():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this is a problem, It's also a problem if the trace function raises, I think you'll need to do this:

# synchronization.pyaclose_forcefully=anyio.aclose_forcefullydefclose_forcefully(sock):
sock.close()
asyncdefaclose(self):
entered_cmgr=Falsetry:
asyncwithTrace("response_closed", logger, self._request, kwargs={}):
entered_cmgr=Trueifnotself._closed:
self._closed=Trueifself._connection._connection_should_close():
awaitself._connection.aclose()
exceptBaseException:
ifentered_cmgr:
raiseifnotself._closed:
self._closed=Trueifself._connection._connection_should_close():
awaitaclose_forcefully(self._connection)
raise

async with Trace("response_closed", logger, request) as trace:
await self._response_closed()
if self._connection_should_close():
await self._network_stream.aclose()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this isn't tracing anymore

@graingertgraingert mentioned this pull request Sep 19, 2024
@rattrayalex

rattrayalex commented Nov 11, 2024

Copy link
Copy Markdown

Any update here? Would contributions be welcome?

@stale

staleBot commented Jun 27, 2025

Copy link
Copy Markdown

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stalestaleBot added the wontfix This will not be worked on label Jun 27, 2025
@T-256

Copy link
Copy Markdown
Contributor

Bump

@stalestaleBot removed the wontfix This will not be worked on label Jun 28, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Development

Successfully merging this pull request may close these issues.

5 participants

@lovelydinosaur@rattrayalex@T-256@graingert@MarkusSintonen