Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BugFix] [Resource Leak] Gracefully Close ZMQ Context upon kernel shutdown #548

Merged
merged 14 commits into from
Jun 22, 2020
6 changes: 6 additions & 0 deletions jupyter_client/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,9 @@ def shutdown_kernel(self, now=False, restart=False):
self.finish_shutdown()

self.cleanup(connection_file=not restart)
# shutdown ZMQ context as we no longer using this kernel
if not restart:
self.context.destroy(linger=100)
jalpan-randeri marked this conversation as resolved.
Show resolved Hide resolved

def restart_kernel(self, now=False, newports=False, **kw):
"""Restarts a kernel with the arguments that were used to launch it.
Expand Down Expand Up @@ -592,6 +595,9 @@ async def shutdown_kernel(self, now=False, restart=False):
await self.finish_shutdown()

self.cleanup(connection_file=not restart)
# shutdown ZMQ context as we no longer using this kernel
if not restart:
self.context.destroy(linger=100)
jalpan-randeri marked this conversation as resolved.
Show resolved Hide resolved

async def restart_kernel(self, now=False, newports=False, **kw):
"""Restarts a kernel with the arguments that were used to launch it.
Expand Down
8 changes: 8 additions & 0 deletions jupyter_client/tests/test_kernelmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def _run_lifecycle(self, km):
km.interrupt_kernel()
self.assertTrue(isinstance(km, KernelManager))
km.shutdown_kernel(now=True)
self.assertTrue(km.context.closed)

def test_tcp_lifecycle(self):
km = self._get_tcp_km()
Expand Down Expand Up @@ -135,6 +136,7 @@ def test_start_new_kernel(self):

self.assertTrue(km.is_alive())
self.assertTrue(kc.is_alive())
self.assertFalse(km.context.closed)

def _env_test_body(self, kc):

Expand All @@ -157,6 +159,7 @@ def test_templated_kspec_env(self):

self.assertTrue(km.is_alive())
self.assertTrue(kc.is_alive())
self.assertFalse(km.context.closed)

self._env_test_body(kc)

Expand Down Expand Up @@ -190,6 +193,7 @@ def test_templated_extra_env(self):

self.assertTrue(km.is_alive())
self.assertTrue(kc.is_alive())
self.assertFalse(km.context.closed)

self._env_test_body(kc)

Expand Down Expand Up @@ -307,6 +311,7 @@ def execute(cmd):
execute('check')

km.shutdown_kernel()
assert km.context.closed


class TestAsyncKernelManager(AsyncTestCase):
Expand Down Expand Up @@ -351,6 +356,7 @@ async def _run_lifecycle(self, km):
self.assertTrue(isinstance(km, AsyncKernelManager))
await km.shutdown_kernel(now=True)
self.assertFalse(await km.is_alive())
self.assertTrue(km.context.closed)

@gen_test
async def test_tcp_lifecycle(self):
Expand Down Expand Up @@ -417,6 +423,7 @@ async def execute(cmd):
finally:
await km.shutdown_kernel(now=True)
kc.stop_channels()
self.assertTrue(km.context.closed)

@gen_test(timeout=10.0)
async def test_start_new_async_kernel(self):
Expand All @@ -431,3 +438,4 @@ async def test_start_new_async_kernel(self):
finally:
await km.shutdown_kernel(now=True)
kc.stop_channels()
self.assertTrue(km.context.closed)