Skip to content

gh-123720: When closing an asyncio server, stop the handlers #124689

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

gvanrossum
Copy link
Member

@gvanrossum gvanrossum commented Sep 27, 2024

Since 3.12, when server.wait_closed() was fixed, cancelling a serve_forever() call would wait for the last handler to exit, which may be never if it is waiting to read from a connection that is never closed by the client. To fix this, we insert a close_clients() call in the exit sequence (between close() and wait_closed()).

The repro shows that in 3.11 you need only a single ^C to stop the server; in 3.12 you need two. The fix indeed undoes that regression.

Some philosophical question remain:

  • Should we call close_clients() in close(), so everyone who closes a server gets the same benefit?
  • Should we use abort_clients() instead? (I think it's better to allow handlers to catch the cancellation and e.g. send a "goodbye" message to the client.)
  • Is this a bugfix (backportable) or a new feature? I'm inclined to call it a bugfix, given the regressions in 3.12 and beyond.

Note that there's still a difference with 3.11: in 3.11, the handler receives a CancelledError; in main with this PR added, the handler receives an empty string, indicating that the connection was closed (by close_clients()). Maybe I should do something that actually cancels the handlers? I will look into the feasibility of this.

@gvanrossum
Copy link
Member Author

The only failing test is the check for a news blurb. Once I've got time for that I'll move forward.

@danpascu
Copy link

I think this fix is incomplete. I believe the __aexit__ method of AbstractServer at

async def __aexit__(self, *exc):
self.close()
await self.wait_closed()
also needs to be modified to include a call to self.close_clients().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants