Skip to content

Commit b4d41a5

Browse files
committed
Nudge kernel on restart
1 parent 364f45a commit b4d41a5

File tree

2 files changed

+47
-17
lines changed

2 files changed

+47
-17
lines changed

notebook/services/kernels/handlers.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,8 @@ def post(self, kernel_id, action):
7878
yield maybe_future(km.interrupt_kernel(kernel_id))
7979
self.set_status(204)
8080
if action == 'restart':
81-
8281
try:
83-
yield maybe_future(km.restart_kernel(kernel_id))
82+
yield maybe_future(km.restart_kernel(kernel_id, channels))
8483
except Exception as e:
8584
self.log.error("Exception restarting kernel", exc_info=True)
8685
self.set_status(500)

notebook/services/kernels/kernelmanager.py

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -304,33 +304,54 @@ def shutdown_kernel(self, kernel_id, now=False, restart=False):
304304

305305
return self.pinned_superclass.shutdown_kernel(self, kernel_id, now=now, restart=restart)
306306

307-
async def restart_kernel(self, kernel_id, now=False):
307+
async def restart_kernel(self, kernel_id, channels, now=False):
308308
"""Restart a kernel by kernel_id"""
309309
self._check_kernel_id(kernel_id)
310310
await maybe_future(self.pinned_superclass.restart_kernel(self, kernel_id, now=now))
311311
kernel = self.get_kernel(kernel_id)
312312
# return a Future that will resolve when the kernel has successfully restarted
313-
channel = kernel.connect_shell()
313+
shell_channel = self.channels['shell']
314+
iopub_channel = self.channels['iopub']
315+
314316
future = Future()
317+
info_future = Future()
318+
iopub_future = Future()
315319

316320
def finish():
317-
"""Common cleanup when restart finishes/fails for any reason."""
318-
if not channel.closed():
319-
channel.close()
321+
"""Common cleanup"""
320322
loop.remove_timeout(timeout)
323+
loop.remove_timeout(nudge_handle)
324+
iopub_channel.stop_on_recv()
325+
shell_channel.stop_on_recv()
321326
kernel.remove_restart_callback(on_restart_failed, 'dead')
322327

323-
def on_reply(msg):
324-
self.log.debug("Kernel info reply received: %s", kernel_id)
325-
finish()
326-
if not future.done():
327-
future.set_result(msg)
328+
def on_shell_reply(msg):
329+
if not info_future.done():
330+
self.log.debug("Nudge: shell info reply received: %s", self.kernel_id)
331+
shell_channel.stop_on_recv()
332+
self.log.debug("Nudge: resolving shell future")
333+
info_future.set_result(msg)
334+
if iopub_future.done():
335+
finish()
336+
self.log.debug("Nudge: resolving main future in shell handler")
337+
future.set_result(info_future.result())
338+
339+
def on_iopub(msg):
340+
if not iopub_future.done():
341+
self.log.debug("Nudge: first IOPub received: %s", self.kernel_id)
342+
iopub_channel.stop_on_recv()
343+
self.log.debug("Nudge: resolving iopub future")
344+
iopub_future.set_result(None)
345+
if info_future.done():
346+
finish()
347+
self.log.debug("Nudge: resolving main future in iopub handler")
348+
future.set_result(info_future.result())
328349

329350
def on_timeout():
330-
self.log.warning("Timeout waiting for kernel_info_reply: %s", kernel_id)
351+
self.log.warning("Nudge: Timeout waiting for kernel_info_reply: %s", self.kernel_id)
331352
finish()
332353
if not future.done():
333-
future.set_exception(TimeoutError("Timeout waiting for restart"))
354+
future.set_exception(TimeoutError("Timeout waiting for nudge"))
334355

335356
def on_restart_failed():
336357
self.log.warning("Restarting kernel failed: %s", kernel_id)
@@ -339,10 +360,20 @@ def on_restart_failed():
339360
future.set_exception(RuntimeError("Restart failed"))
340361

341362
kernel.add_restart_callback(on_restart_failed, 'dead')
342-
kernel.session.send(channel, "kernel_info_request")
343-
channel.on_recv(on_reply)
363+
364+
iopub_channel.on_recv(on_iopub)
365+
shell_channel.on_recv(on_shell_reply)
344366
loop = IOLoop.current()
345-
timeout = loop.add_timeout(loop.time() + self.kernel_info_timeout, on_timeout)
367+
368+
# Nudge the kernel with kernel info requests until we get an IOPub message
369+
def nudge():
370+
self.log.debug("Nudge")
371+
if not future.done():
372+
self.log.debug("nudging")
373+
self.session.send(shell_channel, "kernel_info_request")
374+
nudge_handle = loop.call_later(0.5, nudge)
375+
nudge_handle = loop.call_later(0, nudge)
376+
346377
return future
347378

348379
def notify_connect(self, kernel_id):

0 commit comments

Comments
 (0)