Config option to shut down server after N seconds with no kernels

Thomas Kluyver 9 years ago
parent f763c03d10
commit 9ec57bfdf5

@ -1070,6 +1070,14 @@ class NotebookApp(JupyterApp):
rate_limit_window = Float(3, config=True, help=_("""(sec) Time window used to
check the message and data rate limits."""))
shutdown_no_kernels_timeout = Integer(0, config=True,
help=("Use a positive integer, to shut down the server after N "
"seconds with no kernels running. This can be used together with "
"culling idle kernels (MappingKernelManager.cull_idle_timeout) to "
"shutdown the notebook server when it's not in use. "
"Do not rely on this being accurately timed.")
)
def parse_command_line(self, argv=None):
super(NotebookApp, self).parse_command_line(argv)
@ -1357,6 +1365,26 @@ class NotebookApp(JupyterApp):
# mimetype always needs to be text/css, so we override it here.
mimetypes.add_type('text/css', '.css')
def shutdown_no_kernels(self):
"""Shutdown server on timeout when there are no kernels."""
km = self.kernel_manager
if len(km) == 0:
seconds_since_kernel = \
(utcnow() - km.last_kernel_activity).total_seconds()
self.log.debug("No kernels for %d seconds.",
seconds_since_kernel)
if seconds_since_kernel > self.shutdown_no_kernels_timeout:
self.log.info("No kernels for %d seconds; shutting down.",
seconds_since_kernel)
self.stop()
def init_shutdown_no_kernels(self):
if self.shutdown_no_kernels_timeout > 0:
self.log.info("Will shut down after %d seconds with no kernels.",
self.shutdown_no_kernels_timeout)
pc = ioloop.PeriodicCallback(self.shutdown_no_kernels, 60000)
pc.start()
@catch_config_error
def initialize(self, argv=None):
super(NotebookApp, self).initialize(argv)
@ -1370,6 +1398,7 @@ class NotebookApp(JupyterApp):
self.init_signal()
self.init_server_extensions()
self.init_mime_overrides()
self.init_shutdown_no_kernels()
def cleanup_kernels(self):
"""Shutdown all kernels.

@ -8,6 +8,7 @@
# Distributed under the terms of the Modified BSD License.
from collections import defaultdict
from datetime import datetime, timedelta
from functools import partial
import os
@ -17,14 +18,14 @@ from tornado.ioloop import IOLoop, PeriodicCallback
from jupyter_client.session import Session
from jupyter_client.multikernelmanager import MultiKernelManager
from traitlets import Any, Bool, Dict, List, Unicode, TraitError, Integer, default, validate
from traitlets import (Any, Bool, Dict, List, Unicode, TraitError, Integer,
Instance, default, validate
)
from notebook.utils import to_os_path, exists
from notebook._tz import utcnow, isoformat
from ipython_genutils.py3compat import getcwd
from datetime import timedelta
class MappingKernelManager(MultiKernelManager):
"""A KernelManager that handles notebook mapping and HTTP error handling"""
@ -88,6 +89,13 @@ class MappingKernelManager(MultiKernelManager):
def _default_kernel_buffers(self):
return defaultdict(lambda: {'buffer': [], 'session_key': '', 'channels': {}})
last_kernel_activity = Instance(datetime,
help="The last activity on any kernel, including shutting down a kernel")
def __init__(self, **kwargs):
super(MappingKernelManager, self).__init__(**kwargs)
self.last_kernel_activity = utcnow()
#-------------------------------------------------------------------------
# Methods for managing kernels and sessions
#-------------------------------------------------------------------------
@ -241,6 +249,7 @@ class MappingKernelManager(MultiKernelManager):
kernel._activity_stream.close()
self.stop_buffering(kernel_id)
self._kernel_connections.pop(kernel_id, None)
self.last_kernel_activity = utcnow()
return super(MappingKernelManager, self).shutdown_kernel(kernel_id, now=now)
def restart_kernel(self, kernel_id):
@ -346,7 +355,7 @@ class MappingKernelManager(MultiKernelManager):
def record_activity(msg_list):
"""Record an IOPub message arriving from a kernel"""
kernel.last_activity = utcnow()
self.last_kernel_activity = kernel.last_activity = utcnow()
idents, fed_msg_list = session.feed_identities(msg_list)
msg = session.deserialize(fed_msg_list)

Loading…
Cancel
Save