@@ -77,9 +77,8 @@ async def post(self, kernel_id, action):
7777 await ensure_async (km .interrupt_kernel (kernel_id ))
7878 self .set_status (204 )
7979 if action == 'restart' :
80-
8180 try :
82- await km .restart_kernel (kernel_id )
81+ await km .restart_kernel (kernel_id , km . channels )
8382 except Exception as e :
8483 self .log .error ("Exception restarting kernel" , exc_info = True )
8584 self .set_status (500 )
@@ -127,6 +126,64 @@ def create_stream(self):
127126 self .channels [channel ] = stream = meth (self .kernel_id , identity = identity )
128127 stream .channel = channel
129128
129+ shell_channel = self .channels ['shell' ]
130+ iopub_channel = self .channels ['iopub' ]
131+
132+ future = Future ()
133+ info_future = Future ()
134+ iopub_future = Future ()
135+
136+ def finish ():
137+ """Common cleanup"""
138+ loop .remove_timeout (timeout )
139+ loop .remove_timeout (nudge_handle )
140+ iopub_channel .stop_on_recv ()
141+ shell_channel .stop_on_recv ()
142+
143+ def on_shell_reply (msg ):
144+ if not info_future .done ():
145+ self .log .debug ("Nudge: shell info reply received: %s" , self .kernel_id )
146+ shell_channel .stop_on_recv ()
147+ self .log .debug ("Nudge: resolving shell future" )
148+ info_future .set_result (msg )
149+ if iopub_future .done ():
150+ finish ()
151+ self .log .debug ("Nudge: resolving main future in shell handler" )
152+ future .set_result (info_future .result ())
153+
154+ def on_iopub (msg ):
155+ if not iopub_future .done ():
156+ self .log .debug ("Nudge: first IOPub received: %s" , self .kernel_id )
157+ iopub_channel .stop_on_recv ()
158+ self .log .debug ("Nudge: resolving iopub future" )
159+ iopub_future .set_result (None )
160+ if info_future .done ():
161+ finish ()
162+ self .log .debug ("Nudge: resolving main future in iopub handler" )
163+ future .set_result (info_future .result ())
164+
165+ def on_timeout ():
166+ self .log .warning ("Nudge: Timeout waiting for kernel_info_reply: %s" , self .kernel_id )
167+ finish ()
168+ if not future .done ():
169+ future .set_exception (TimeoutError ("Timeout waiting for nudge" ))
170+
171+ iopub_channel .on_recv (on_iopub )
172+ shell_channel .on_recv (on_shell_reply )
173+ loop = IOLoop .current ()
174+
175+ # Nudge the kernel with kernel info requests until we get an IOPub message
176+ def nudge ():
177+ self .log .debug ("Nudge" )
178+ if not future .done ():
179+ self .log .debug ("nudging" )
180+ self .session .send (shell_channel , "kernel_info_request" )
181+ nudge_handle = loop .call_later (0.5 , nudge )
182+ nudge_handle = loop .call_later (0 , nudge )
183+
184+ timeout = loop .add_timeout (loop .time () + self .kernel_info_timeout , on_timeout )
185+ return future
186+
130187 def request_kernel_info (self ):
131188 """send a request for kernel_info"""
132189 km = self .kernel_manager
@@ -192,6 +249,7 @@ def initialize(self):
192249 super (ZMQChannelsHandler , self ).initialize ()
193250 self .zmq_stream = None
194251 self .channels = {}
252+ self .kernel_manager .channels = self .channels
195253 self .kernel_id = None
196254 self .kernel_info_channel = None
197255 self ._kernel_info_future = Future ()
@@ -249,7 +307,7 @@ async def _register_session(self):
249307 await stale_handler .close ()
250308 self ._open_sessions [self .session_key ] = self
251309
252- def open (self , kernel_id ):
310+ async def open (self , kernel_id ):
253311 super (ZMQChannelsHandler , self ).open ()
254312 km = self .kernel_manager
255313 km .notify_connect (kernel_id )
@@ -265,9 +323,11 @@ def open(self, kernel_id):
265323 for channel , msg_list in replay_buffer :
266324 stream = self .channels [channel ]
267325 self ._on_zmq_reply (stream , msg_list )
326+ connected = Future ()
327+ connected .set_result (None )
268328 else :
269329 try :
270- self .create_stream ()
330+ connected = self .create_stream ()
271331 except web .HTTPError as e :
272332 self .log .error ("Error opening stream: %s" , e )
273333 # WebSockets don't response to traditional error codes so we
@@ -281,8 +341,14 @@ def open(self, kernel_id):
281341 km .add_restart_callback (self .kernel_id , self .on_kernel_restarted )
282342 km .add_restart_callback (self .kernel_id , self .on_restart_failed , 'dead' )
283343
284- for channel , stream in self .channels .items ():
285- stream .on_recv_stream (self ._on_zmq_reply )
344+ def subscribe (value ):
345+ for channel , stream in self .channels .items ():
346+ stream .on_recv_stream (self ._on_zmq_reply )
347+
348+ connected .add_done_callback (subscribe )
349+
350+ return connected
351+
286352
287353 def on_message (self , msg ):
288354 if not self .channels :
0 commit comments