-
-
Notifications
You must be signed in to change notification settings - Fork 31
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
handle exception when websocket server start room failed #289
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ | |
|
||
from jupyter_server.auth import authorized | ||
from jupyter_server.base.handlers import APIHandler, JupyterHandler | ||
from jupyter_server.utils import ensure_async | ||
from jupyter_ydoc import ydocs as YDOCS | ||
from pycrdt_websocket.websocket_server import YRoom | ||
from pycrdt_websocket.ystore import BaseYStore | ||
|
@@ -70,6 +71,7 @@ def create_task(self, aw): | |
task.add_done_callback(self._background_tasks.discard) | ||
|
||
async def prepare(self): | ||
await ensure_async(super().prepare()) | ||
if not self._websocket_server.started.is_set(): | ||
self.create_task(self._websocket_server.start()) | ||
await self._websocket_server.started.wait() | ||
|
@@ -110,12 +112,26 @@ async def prepare(self): | |
# it is a transient document (e.g. awareness) | ||
self.room = TransientRoom(self._room_id, self.log) | ||
|
||
await self._websocket_server.start_room(self.room) | ||
self._websocket_server.add_room(self._room_id, self.room) | ||
try: | ||
await self._websocket_server.start_room(self.room) | ||
except Exception as e: | ||
self.log.error("Room %s failed to start on websocket server", self._room_id) | ||
# Clean room | ||
await self.room.stop() | ||
self.log.info("Room %s deleted", self._room_id) | ||
self._emit(LogLevel.INFO, "clean", "Room deleted.") | ||
|
||
res = super().prepare() | ||
if res is not None: | ||
return await res | ||
# Clean the file loader in file loader mapping if there are not any rooms using it | ||
_, _, file_id = decode_file_path(self._room_id) | ||
file = self._file_loaders[file_id] | ||
if file.number_of_subscriptions == 0 or ( | ||
file.number_of_subscriptions == 1 and self._room_id in file._subscriptions | ||
): | ||
self.log.info("Deleting file %s", file.path) | ||
await self._file_loaders.remove(file_id) | ||
self._emit(LogLevel.INFO, "clean", "file loader removed.") | ||
raise e | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should the exception be raised, or just logged? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it should be raised when task group is not active and the request to set up websocket will fail and UI will retry. We should not fail silently here if task group is not active. |
||
self._websocket_server.add_room(self._room_id, self.room) | ||
|
||
def initialize( | ||
self, | ||
|
@@ -134,6 +150,8 @@ def initialize( | |
self._document_save_delay = document_save_delay | ||
self._websocket_server = ywebsocket_server | ||
self._message_queue = asyncio.Queue() | ||
self._room_id = "" | ||
self.room = None | ||
|
||
@property | ||
def path(self): | ||
|
@@ -227,7 +245,7 @@ async def send(self, message): | |
try: | ||
self.write_message(message, binary=True) | ||
except Exception as e: | ||
self.log.debug("Failed to write message", exc_info=e) | ||
self.log.error("Failed to write message", exc_info=e) | ||
|
||
async def recv(self): | ||
""" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -161,7 +161,10 @@ async def stop(self) -> None: | |
Cancels the save task and unsubscribes from the file. | ||
""" | ||
await super().stop() | ||
try: | ||
await super().stop() | ||
except RuntimeError: | ||
pass | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be done in |
||
# TODO: Should we cancel or wait ? | ||
if self._saving_document: | ||
self._saving_document.cancel() | ||
|
@@ -299,3 +302,12 @@ async def _broadcast_updates(self): | |
await super()._broadcast_updates() | ||
except asyncio.CancelledError: | ||
pass | ||
|
||
async def stop(self) -> None: | ||
""" | ||
Stop the room. | ||
""" | ||
try: | ||
await super().stop() | ||
except RuntimeError: | ||
pass | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be done in |
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.
Maybe I'm missing something, but didn't we introduced the YRoom exception handler just for that purpose? It seems we are bypassing all the work we did in
pycrdt-websocket
and instead directly handling the exception here.