1010from jupyter_ydoc .ybasedoc import YBaseDoc
1111from pycrdt import Doc
1212from pycrdt_websocket .ystore import BaseYStore
13- from traitlets import Bool , Float , Type
13+ from traitlets import Bool , Float , Type , Set , Instance
1414
1515from .handlers import DocSessionHandler , YDocWebSocketHandler
1616from .loaders import FileLoaderMapping
@@ -75,6 +75,10 @@ class YDocExtension(ExtensionApp):
7575 model.""" ,
7676 )
7777
78+ _running_ywebsocket_server = Instance (asyncio .Task , allow_none = True )
79+ ywebsocket_server = Instance (JupyterWebsocketServer , allow_none = True )
80+
81+
7882 def initialize (self ):
7983 super ().initialize ()
8084 self .serverapp .event_logger .register_event_schema (EVENTS_SCHEMA_PATH )
@@ -90,6 +94,13 @@ def initialize_settings(self):
9094 }
9195 )
9296
97+ self .ywebsocket_server = JupyterWebsocketServer (
98+ rooms_ready = False ,
99+ auto_clean_rooms = False ,
100+ ystore_class = self .ystore_class ,
101+ log = self .log ,
102+ )
103+
93104 def initialize_handlers (self ):
94105 self .serverapp .web_app .settings .setdefault (
95106 "page_config_data" ,
@@ -103,13 +114,6 @@ def initialize_handlers(self):
103114 for k , v in self .config .get (self .ystore_class .__name__ , {}).items ():
104115 setattr (self .ystore_class , k , v )
105116
106- self .ywebsocket_server = JupyterWebsocketServer (
107- rooms_ready = False ,
108- auto_clean_rooms = False ,
109- ystore_class = self .ystore_class ,
110- log = self .log ,
111- )
112-
113117 # self.settings is local to the ExtensionApp but here we need
114118 # the global app settings in which the file id manager will register
115119 # itself maybe at a later time.
@@ -134,6 +138,33 @@ def initialize_handlers(self):
134138 ]
135139 )
136140
141+ async def start_extension (self ):
142+ """Start the y-websocket server.
143+ """
144+ self .log .info ("Starting the Collaborative Document Server." )
145+
146+ def _restart_or_teardown_yserver (_ ):
147+ """If the y websocket server task stopped due to an exception, restart it.
148+
149+ If the y-websocket server was cancelled on purpose, tear it down.
150+ """
151+ self .ywebsocket_server ._started = None
152+ self .ywebsocket_server ._starting = False
153+ self .ywebsocket_server ._task_group = None
154+ # If an exception was raised, restart the websocket server.
155+ if self ._running_ywebsocket_server .exception ():
156+ self .log .error (self ._running_ywebsocket_server .exception ())
157+ self .log .warning ("Restarting the Collaborative Document Server." )
158+ self ._running_ywebsocket_server = asyncio .create_task (self .ywebsocket_server .start ())
159+ self ._running_ywebsocket_server .add_done_callback (_restart_or_teardown_yserver )
160+ return
161+ self .log .info ("Stopping the Collaborative Document Server." )
162+
163+ # Start the websocket server
164+ self ._running_ywebsocket_server = asyncio .create_task (self .ywebsocket_server .start ())
165+ # If the websocket crashes for any reason, let's restart it automatically and log errors.
166+ self ._running_ywebsocket_server .add_done_callback (_restart_or_teardown_yserver )
167+
137168 async def get_document (
138169 self : YDocExtension ,
139170 * ,
0 commit comments