Merge pull request #606 from minrk/restart-kernel-stop

wait for kernel to restart
This commit is contained in:
Brian E. Granger 2015-10-19 15:17:28 -04:00
commit 3c31700fb8
3 changed files with 54 additions and 6 deletions

View File

@ -72,16 +72,22 @@ class KernelActionHandler(APIHandler):
@web.authenticated
@json_errors
@gen.coroutine
def post(self, kernel_id, action):
km = self.kernel_manager
if action == 'interrupt':
km.interrupt_kernel(kernel_id)
self.set_status(204)
if action == 'restart':
km.restart_kernel(kernel_id)
model = km.kernel_model(kernel_id)
self.set_header('Location', '{0}api/kernels/{1}'.format(self.base_url, kernel_id))
self.write(json.dumps(model))
try:
yield gen.maybe_future(km.restart_kernel(kernel_id))
except Exception as e:
self.log.error("Exception restarting kernel", exc_info=True)
self.set_status(500)
else:
model = km.kernel_model(kernel_id)
self.write(json.dumps(model))
self.finish()

View File

@ -9,7 +9,9 @@
import os
from tornado import web
from tornado import gen, web
from tornado.concurrent import Future
from tornado.ioloop import IOLoop
from jupyter_client.multikernelmanager import MultiKernelManager
from traitlets import List, Unicode, TraitError
@ -99,6 +101,47 @@ class MappingKernelManager(MultiKernelManager):
self._check_kernel_id(kernel_id)
super(MappingKernelManager, self).shutdown_kernel(kernel_id, now=now)
def restart_kernel(self, kernel_id):
"""Restart a kernel by kernel_id"""
self._check_kernel_id(kernel_id)
super(MappingKernelManager, self).restart_kernel(kernel_id)
kernel = self.get_kernel(kernel_id)
# return a Future that will resolve when the kernel has successfully restarted
channel = kernel.connect_shell()
future = Future()
def finish():
"""Common cleanup when restart finishes/fails for any reason."""
if not channel.closed:
channel.close()
loop.remove_timeout(timeout)
kernel.remove_restart_callback(on_restart_failed, 'dead')
def on_reply(msg):
self.log.debug("Kernel info reply received: %s", kernel_id)
finish()
if not future.done():
future.set_result(msg)
def on_timeout():
self.log.warn("Timeout waiting for kernel_info_reply: %s", kernel_id)
finish()
if not future.done():
future.set_exception(gen.TimeoutError("Timeout waiting for restart"))
def on_restart_failed():
self.log.warn("Restarting kernel failed: %s", kernel_id)
finish()
if not future.done():
future.set_exception(RuntimeError("Restart failed"))
kernel.add_restart_callback(on_restart_failed, 'dead')
kernel.session.send(channel, "kernel_info_request")
channel.on_recv(on_reply)
loop = IOLoop.current()
timeout = loop.add_timeout(loop.time() + 30, on_timeout)
return future
def kernel_model(self, kernel_id):
"""Return a dictionary of kernel information described in the
JSON standard model."""

View File

@ -114,7 +114,6 @@ class KernelAPITest(NotebookTestBase):
# Restart a kernel
r = self.kern_api.restart(kern2['id'])
self.assertEqual(r.headers['Location'], url_path_join(self.url_prefix, 'api/kernels', kern2['id']))
rekern = r.json()
self.assertEqual(rekern['id'], kern2['id'])
self.assertEqual(rekern['name'], kern2['name'])