Skip to content

Commit 7797238

Browse files
committed
Add support for async kernel management via subclassing
Introduced async subclasses that derive from synchronous classes, overriding appropriate methods with async support.
1 parent 6fffba7 commit 7797238

File tree

10 files changed

+746
-189
lines changed

10 files changed

+746
-189
lines changed

jupyter_client/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from .connect import *
55
from .launcher import *
66
from .client import KernelClient
7-
from .manager import KernelManager, run_kernel
7+
from .manager import KernelManager, AsyncKernelManager, run_kernel
88
from .blocking import BlockingKernelClient
99
from .asynchronous import AsyncKernelClient
10-
from .multikernelmanager import MultiKernelManager
10+
from .multikernelmanager import MultiKernelManager, AsyncMultiKernelManager

jupyter_client/discovery.py

Lines changed: 0 additions & 131 deletions
This file was deleted.

jupyter_client/ioloop/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
from .manager import IOLoopKernelManager
2-
from .restarter import IOLoopKernelRestarter
1+
from .manager import IOLoopKernelManager, AsyncIOLoopKernelManager
2+
from .restarter import IOLoopKernelRestarter, AsyncIOLoopKernelRestarter

jupyter_client/ioloop/manager.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
Type,
1414
)
1515

16-
from jupyter_client.manager import KernelManager
17-
from .restarter import IOLoopKernelRestarter
16+
from jupyter_client.manager import KernelManager, AsyncKernelManager
17+
from .restarter import IOLoopKernelRestarter, AsyncIOLoopKernelRestarter
1818

1919

2020
def as_zmqstream(f):
@@ -23,9 +23,11 @@ def wrapped(self, *args, **kwargs):
2323
return ZMQStream(socket, self.loop)
2424
return wrapped
2525

26+
2627
class IOLoopKernelManager(KernelManager):
2728

2829
loop = Instance('tornado.ioloop.IOLoop')
30+
2931
def _loop_default(self):
3032
return ioloop.IOLoop.current()
3133

@@ -61,3 +63,43 @@ def stop_restarter(self):
6163
connect_iopub = as_zmqstream(KernelManager.connect_iopub)
6264
connect_stdin = as_zmqstream(KernelManager.connect_stdin)
6365
connect_hb = as_zmqstream(KernelManager.connect_hb)
66+
67+
68+
class AsyncIOLoopKernelManager(AsyncKernelManager):
69+
70+
loop = Instance('tornado.ioloop.IOLoop')
71+
72+
def _loop_default(self):
73+
return ioloop.IOLoop.current()
74+
75+
restarter_class = Type(
76+
default_value=AsyncIOLoopKernelRestarter,
77+
klass=AsyncIOLoopKernelRestarter,
78+
help=(
79+
'Type of KernelRestarter to use. '
80+
'Must be a subclass of IOLoopKernelRestarter.\n'
81+
'Override this to customize how kernel restarts are managed.'
82+
),
83+
config=True,
84+
)
85+
_restarter = Instance('jupyter_client.ioloop.AsyncIOLoopKernelRestarter', allow_none=True)
86+
87+
def start_restarter(self):
88+
if self.autorestart and self.has_kernel:
89+
if self._restarter is None:
90+
self._restarter = self.restarter_class(
91+
kernel_manager=self, loop=self.loop,
92+
parent=self, log=self.log
93+
)
94+
self._restarter.start()
95+
96+
def stop_restarter(self):
97+
if self.autorestart:
98+
if self._restarter is not None:
99+
self._restarter.stop()
100+
self._restarter = None
101+
102+
connect_shell = as_zmqstream(AsyncKernelManager.connect_shell)
103+
connect_iopub = as_zmqstream(AsyncKernelManager.connect_iopub)
104+
connect_stdin = as_zmqstream(AsyncKernelManager.connect_stdin)
105+
connect_hb = as_zmqstream(AsyncKernelManager.connect_hb)

jupyter_client/ioloop/restarter.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,20 @@
1010
from __future__ import absolute_import
1111
import warnings
1212

13+
from tornado import gen
1314
from zmq.eventloop import ioloop
1415

1516
from jupyter_client.restarter import KernelRestarter
1617
from traitlets import (
1718
Instance,
1819
)
1920

21+
2022
class IOLoopKernelRestarter(KernelRestarter):
2123
"""Monitor and autorestart a kernel."""
2224

2325
loop = Instance('tornado.ioloop.IOLoop')
26+
2427
def _loop_default(self):
2528
warnings.warn("IOLoopKernelRestarter.loop is deprecated in jupyter-client 5.2",
2629
DeprecationWarning, stacklevel=4,
@@ -42,3 +45,48 @@ def stop(self):
4245
if self._pcallback is not None:
4346
self._pcallback.stop()
4447
self._pcallback = None
48+
49+
50+
class AsyncIOLoopKernelRestarter(IOLoopKernelRestarter):
51+
52+
def start(self):
53+
"""Start the polling of the kernel."""
54+
if self._pcallback is None:
55+
self._pcallback = ioloop.PeriodicCallback(
56+
self.poll, 1000*self.time_to_dead,
57+
)
58+
self._pcallback.start()
59+
60+
@gen.coroutine
61+
def poll(self):
62+
if self.debug:
63+
self.log.debug('Polling kernel...')
64+
is_alive = yield gen.maybe_future(self.kernel_manager.is_alive())
65+
if not is_alive:
66+
if self._restarting:
67+
self._restart_count += 1
68+
else:
69+
self._restart_count = 1
70+
71+
if self._restart_count >= self.restart_limit:
72+
self.log.warning("AsyncIOLoopKernelRestarter: restart failed")
73+
self._fire_callbacks('dead')
74+
self._restarting = False
75+
self._restart_count = 0
76+
self.stop()
77+
else:
78+
newports = self.random_ports_until_alive and self._initial_startup
79+
self.log.info('AsyncIOLoopKernelRestarter: restarting kernel (%i/%i), %s random ports',
80+
self._restart_count,
81+
self.restart_limit,
82+
'new' if newports else 'keep'
83+
)
84+
self._fire_callbacks('restart')
85+
yield self.kernel_manager.restart_kernel(now=True, newports=newports)
86+
self._restarting = True
87+
else:
88+
if self._initial_startup:
89+
self._initial_startup = False
90+
if self._restarting:
91+
self.log.debug("AsyncIOLoopKernelRestarter: restart apparently succeeded")
92+
self._restarting = False

0 commit comments

Comments
 (0)