Skip to content
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

Refactor room and server tasks cleanup #76

Closed
wants to merge 2 commits into from

Conversation

martinRenou
Copy link

@martinRenou martinRenou commented Jun 6, 2023

This is partly taken from jupyter_collaboration.

The user API gets broken by this PR (making some APIs async that were sync before).

ypy_websocket/websocket_server.py Outdated Show resolved Hide resolved
self._broadcast_task.cancel()
await self._broadcast_task
Copy link
Collaborator

Choose a reason for hiding this comment

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

Awaiting the cancelled task will raise a CancelledError.

Suggested change
await self._broadcast_task

Copy link
Author

Choose a reason for hiding this comment

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

It does not seem to raise a CancelledError when I run this, unless it is caught somewhere and silently passing?

How do you make sure the task finished cancelling?

Copy link
Collaborator

Choose a reason for hiding this comment

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

How do you make sure the task finished cancelling?

Then you need to catch CancelledError:

Suggested change
await self._broadcast_task
try:
await self._broadcast_task
except asyncio.CancelledError:
pass

Copy link
Author

Choose a reason for hiding this comment

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

Isn't the CancelledError the thing that gets triggered in the task code when it is being cancelled?

Sorry if it's a dumb question, I'm new to these things.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes CancelledError is raised in the task, so since we're awaiting that task we should catch the exception.
But thinking about it I think we should just use AnyIO, with which all these things come for free.

Copy link
Author

Choose a reason for hiding this comment

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

I see, so we'd need a restructure if we go with AnyIO

Copy link
Author

@martinRenou martinRenou Jun 7, 2023

Choose a reason for hiding this comment

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

But what happens if you want to cancel a task group from outside the context manager, can you do it?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, I'm going to open a PR to show what it would look like.

Copy link
Author

Choose a reason for hiding this comment

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

thanks.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I opened #77.

Co-authored-by: David Brochart <david.brochart@gmail.com>
@fcollonval
Copy link
Collaborator

fcollonval commented Jun 7, 2023

There is a while True loop that eagerly catch all exceptions that needs also to be escaped in case of cancellation:

while True:
update = await self._update_queue.get()
message = create_update_message(update)
try:
await self._websocket.send(message)
except Exception:
pass

In the PR of jupyter_collaboration for improving the clean-up, I miss that point from Python documentation:

In case asyncio.CancelledError is explicitly caught, it should generally be propagated when clean-up is complete.
Source: https://docs.python.org/3/library/asyncio-task.html#task-cancellation

So it was a mistake to wait for the task after calling cancel on them. And the CancelledError should be propagated.

For example, the while loop should become:

 while True: 
     update = await self._update_queue.get() 
     message = create_update_message(update) 
     try: 
         await self._websocket.send(message) 
     except asyncio.CancelledError:
         raise
     except Exception: 
         pass 

@martinRenou
Copy link
Author

martinRenou commented Jun 7, 2023

Thank you for your comment @fcollonval ! I have a try.

@davidbrochart
Copy link
Collaborator

We should close this PR in favor of #77.

@davidbrochart davidbrochart mentioned this pull request Jun 15, 2023
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.

3 participants