diff --git a/notebook/services/kernels/kernelmanager.py b/notebook/services/kernels/kernelmanager.py index cc739afec..6297eb5ad 100644 --- a/notebook/services/kernels/kernelmanager.py +++ b/notebook/services/kernels/kernelmanager.py @@ -115,7 +115,7 @@ class MappingKernelManager(MultiKernelManager): def finish(): """Common cleanup when restart finishes/fails for any reason.""" - if not channel.closed: + if not channel.closed(): channel.close() loop.remove_timeout(timeout) kernel.remove_restart_callback(on_restart_failed, 'dead') diff --git a/notebook/tests/launchnotebook.py b/notebook/tests/launchnotebook.py index 7e24ee2da..2537a5b9a 100644 --- a/notebook/tests/launchnotebook.py +++ b/notebook/tests/launchnotebook.py @@ -18,6 +18,7 @@ except ImportError: from mock import patch #py2 from tornado.ioloop import IOLoop +import zmq import jupyter_core.paths from ..notebookapp import NotebookApp @@ -132,6 +133,16 @@ class NotebookTestBase(TestCase): cls.notebook_dir.cleanup() cls.env_patch.stop() cls.path_patch.stop() + # cleanup global zmq Context, to ensure we aren't leaving dangling sockets + def cleanup_zmq(): + zmq.Context.instance().term() + t = Thread(target=cleanup_zmq) + t.daemon = True + t.start() + t.join(5) # give it a few seconds to clean up (this should be immediate) + # if term never returned, there's zmq stuff still open somewhere, so shout about it. + if t.is_alive(): + raise RuntimeError("Failed to teardown zmq Context, open sockets likely left lying around.") @classmethod def base_url(cls):