diff --git a/IPython/frontend/html/notebook/handlers.py b/IPython/frontend/html/notebook/handlers.py index bc5dc9e..f2030e7 100644 --- a/IPython/frontend/html/notebook/handlers.py +++ b/IPython/frontend/html/notebook/handlers.py @@ -344,7 +344,7 @@ class KernelHandler(AuthenticatedHandler): @web.authenticated def delete(self, kernel_id): km = self.application.kernel_manager - km.kill_kernel(kernel_id) + km.shutdown_kernel(kernel_id) self.set_status(204) self.finish() diff --git a/IPython/frontend/html/notebook/kernelmanager.py b/IPython/frontend/html/notebook/kernelmanager.py index 3ea27a9..a31a58a 100644 --- a/IPython/frontend/html/notebook/kernelmanager.py +++ b/IPython/frontend/html/notebook/kernelmanager.py @@ -43,7 +43,7 @@ class MultiKernelManager(LoggingConfigurable): """A class for managing multiple kernels.""" kernel_manager_class = DottedObjectName( - "IPython.zmq.kernelmanager.KernelManager", config=True, + "IPython.zmq.blockingkernelmanager.BlockingKernelManager", config=True, help="""The kernel manager class. This is configurable to allow subclassing of the KernelManager for customized behavior. """ @@ -87,9 +87,22 @@ class MultiKernelManager(LoggingConfigurable): config=self.config, ) km.start_kernel(**kwargs) + # start just the shell channel, needed for graceful restart + km.start_channels(shell=True, sub=False, stdin=False, hb=False) self._kernels[kernel_id] = km return kernel_id + def shutdown_kernel(self, kernel_id): + """Shutdown a kernel by its kernel uuid. + + Parameters + ========== + kernel_id : uuid + The id of the kernel to shutdown. + """ + self.get_kernel(kernel_id).shutdown_kernel() + del self._kernels[kernel_id] + def kill_kernel(self, kernel_id): """Kill a kernel by its kernel uuid. @@ -267,6 +280,13 @@ class MappingKernelManager(MultiKernelManager): self.log.info("Using existing kernel: %s" % kernel_id) return kernel_id + def shutdown_kernel(self, kernel_id): + """Shutdown a kernel and remove its notebook association.""" + self._check_kernel_id(kernel_id) + super(MappingKernelManager, self).shutdown_kernel(kernel_id) + self.delete_mapping_for_kernel(kernel_id) + self.log.info("Kernel shutdown: %s" % kernel_id) + def kill_kernel(self, kernel_id): """Kill a kernel and remove its notebook association.""" self._check_kernel_id(kernel_id) @@ -284,7 +304,7 @@ class MappingKernelManager(MultiKernelManager): """Restart a kernel while keeping clients connected.""" self._check_kernel_id(kernel_id) km = self.get_kernel(kernel_id) - km.restart_kernel(now=True) + km.restart_kernel() self.log.info("Kernel restarted: %s" % kernel_id) return kernel_id diff --git a/IPython/frontend/html/notebook/notebookapp.py b/IPython/frontend/html/notebook/notebookapp.py index 3b49b39..6059fb3 100644 --- a/IPython/frontend/html/notebook/notebookapp.py +++ b/IPython/frontend/html/notebook/notebookapp.py @@ -532,9 +532,9 @@ class NotebookApp(BaseIPythonApplication): """ self.log.info('Shutting down kernels') km = self.kernel_manager - # copy list, since kill_kernel deletes keys + # copy list, since shutdown_kernel deletes keys for kid in list(km.kernel_ids): - km.kill_kernel(kid) + km.shutdown_kernel(kid) def start(self): ip = self.ip if self.ip else '[all ip addresses on your system]'