Show More
@@ -41,22 +41,37 b' class KernelRestarter(LoggingConfigurable):' | |||||
41 | help="""Kernel heartbeat interval in seconds.""" |
|
41 | help="""Kernel heartbeat interval in seconds.""" | |
42 | ) |
|
42 | ) | |
43 |
|
43 | |||
|
44 | _pcallback = None | |||
|
45 | ||||
44 | def __init__(self, **kwargs): |
|
46 | def __init__(self, **kwargs): | |
45 | super(KernelRestarter, self).__init__(**kwargs) |
|
47 | super(KernelRestarter, self).__init__(**kwargs) | |
46 |
|
48 | |||
47 | def start(self): |
|
49 | def start(self): | |
48 | self.pc = ioloop.PeriodicCallback(self.poll, self.time_to_dead, self.ioloop) |
|
50 | """Start the polling of the kernel.""" | |
49 | self.pc.start() |
|
51 | if self._pcallback is None: | |
|
52 | self._pcallback = ioloop.PeriodicCallback( | |||
|
53 | self._poll, 1000*self.time_to_dead, self.ioloop | |||
|
54 | ) | |||
|
55 | self._pcallback.start() | |||
|
56 | ||||
|
57 | def stop(self): | |||
|
58 | """Stop the kernel polling.""" | |||
|
59 | if self._pcallback is not None: | |||
|
60 | self._pcallback.stop() | |||
50 |
|
61 | |||
51 |
def |
|
62 | def clear(self): | |
|
63 | """Clear the underlying PeriodicCallback.""" | |||
|
64 | self.stop() | |||
|
65 | if self._pcallback is not None: | |||
|
66 | self._pcallback = None | |||
|
67 | ||||
|
68 | def _poll(self): | |||
52 | if not self.kernel_manager.is_alive(): |
|
69 | if not self.kernel_manager.is_alive(): | |
53 | self.stop() |
|
70 | self.stop() | |
54 | # This restart event should leave the connection file in place so |
|
71 | # This restart event should leave the connection file in place so | |
55 | # the ports are the same. Because this takes place below the |
|
72 | # the ports are the same. Because this takes place below the | |
56 | # MappingKernelManager, the kernel_id will also remain the same. |
|
73 | # MappingKernelManager, the kernel_id will also remain the same. | |
|
74 | self.log('KernelRestarter: restarting kernel') | |||
57 | self.kernel_manager.restart_kernel(now=True); |
|
75 | self.kernel_manager.restart_kernel(now=True); | |
58 | self.start() |
|
76 | self.start() | |
59 |
|
77 | |||
60 | def stop(self): |
|
|||
61 | self.pc.stop() |
|
|||
62 | self.pc = None |
|
@@ -23,12 +23,15 b' import uuid' | |||||
23 |
|
23 | |||
24 | import zmq |
|
24 | import zmq | |
25 | from zmq.eventloop.zmqstream import ZMQStream |
|
25 | from zmq.eventloop.zmqstream import ZMQStream | |
|
26 | from zmq.eventloop import ioloop | |||
26 |
|
27 | |||
27 | from IPython.config.configurable import LoggingConfigurable |
|
28 | from IPython.config.configurable import LoggingConfigurable | |
28 | from IPython.utils.importstring import import_item |
|
29 | from IPython.utils.importstring import import_item | |
29 | from IPython.utils.traitlets import ( |
|
30 | from IPython.utils.traitlets import ( | |
30 | Instance, Dict, Unicode, Any, DottedObjectName, |
|
31 | Instance, Dict, Unicode, Any, DottedObjectName, Bool | |
31 | ) |
|
32 | ) | |
|
33 | # from IPython.kernel.kernelrestarter import KernelRestarter | |||
|
34 | ||||
32 | #----------------------------------------------------------------------------- |
|
35 | #----------------------------------------------------------------------------- | |
33 | # Classes |
|
36 | # Classes | |
34 | #----------------------------------------------------------------------------- |
|
37 | #----------------------------------------------------------------------------- | |
@@ -61,7 +64,7 b' class MultiKernelManager(LoggingConfigurable):' | |||||
61 | def _loop_default(self): |
|
64 | def _loop_default(self): | |
62 | return ioloop.IOLoop.instance() |
|
65 | return ioloop.IOLoop.instance() | |
63 |
|
66 | |||
64 |
autorestart = Bool( |
|
67 | autorestart = Bool(False, config=True, | |
65 | help="""Should we autorestart kernels that die.""" |
|
68 | help="""Should we autorestart kernels that die.""" | |
66 | ) |
|
69 | ) | |
67 |
|
70 | |||
@@ -83,18 +86,29 b' class MultiKernelManager(LoggingConfigurable):' | |||||
83 | def __contains__(self, kernel_id): |
|
86 | def __contains__(self, kernel_id): | |
84 | return kernel_id in self._kernels |
|
87 | return kernel_id in self._kernels | |
85 |
|
88 | |||
86 |
def start_ |
|
89 | def start_restarter(self, kernel_id): | |
87 |
km = self.get_kernel(kernel_id) |
|
90 | km = self.get_kernel(kernel_id) | |
88 | if self.autorestart: |
|
91 | if self.autorestart: | |
89 |
kr = |
|
92 | kr = self._restarters.get(kernel_id, None) | |
90 | kernel_manager=km, loop=self.loop, |
|
93 | if kr is None: | |
91 | config=self.config, log=self.log |
|
94 | kr = KernelRestarter( | |
92 | ) |
|
95 | kernel_manager=km, loop=self.loop, | |
|
96 | config=self.config, log=self.log | |||
|
97 | ) | |||
|
98 | self._restarters[kernel_id] = kr | |||
93 | kr.start() |
|
99 | kr.start() | |
94 | self._restarters[kernel_id] = kr |
|
|||
95 |
|
100 | |||
96 |
def stop_ |
|
101 | def stop_restarter(self, kernel_id): | |
|
102 | if self.autorestart: | |||
|
103 | kr = self._restarters.get(kernel_id, None) | |||
|
104 | if kr is not None: | |||
|
105 | kr.stop() | |||
97 |
|
106 | |||
|
107 | def clear_restarter(self, kernel_id): | |||
|
108 | if self.autorestart: | |||
|
109 | kr = self._restarters.pop(kernel_id, None) | |||
|
110 | if kr is not None: | |||
|
111 | kr.stop() | |||
98 |
|
112 | |||
99 | def start_kernel(self, **kwargs): |
|
113 | def start_kernel(self, **kwargs): | |
100 | """Start a new kernel. |
|
114 | """Start a new kernel. | |
@@ -121,7 +135,7 b' class MultiKernelManager(LoggingConfigurable):' | |||||
121 | # start just the shell channel, needed for graceful restart |
|
135 | # start just the shell channel, needed for graceful restart | |
122 | km.start_channels(shell=True, iopub=False, stdin=False, hb=False) |
|
136 | km.start_channels(shell=True, iopub=False, stdin=False, hb=False) | |
123 | self._kernels[kernel_id] = km |
|
137 | self._kernels[kernel_id] = km | |
124 |
self.start_ |
|
138 | self.start_restarter(kernel_id) | |
125 | return kernel_id |
|
139 | return kernel_id | |
126 |
|
140 | |||
127 | def shutdown_kernel(self, kernel_id, now=False): |
|
141 | def shutdown_kernel(self, kernel_id, now=False): | |
@@ -135,11 +149,11 b' class MultiKernelManager(LoggingConfigurable):' | |||||
135 | Should the kernel be shutdown forcibly using a signal. |
|
149 | Should the kernel be shutdown forcibly using a signal. | |
136 | """ |
|
150 | """ | |
137 | k = self.get_kernel(kernel_id) |
|
151 | k = self.get_kernel(kernel_id) | |
138 |
self.stop_ |
|
152 | self.stop_restarter(kernel_id) | |
139 | k.shutdown_kernel(now=now) |
|
153 | k.shutdown_kernel(now=now) | |
140 | k.shell_channel.stop() |
|
154 | k.shell_channel.stop() | |
141 | del self._kernels[kernel_id] |
|
155 | del self._kernels[kernel_id] | |
142 |
self. |
|
156 | self.clear_restarter(kernel_id) | |
143 |
|
157 | |||
144 | def shutdown_all(self, now=False): |
|
158 | def shutdown_all(self, now=False): | |
145 | """Shutdown all kernels.""" |
|
159 | """Shutdown all kernels.""" | |
@@ -178,9 +192,9 b' class MultiKernelManager(LoggingConfigurable):' | |||||
178 | The id of the kernel to interrupt. |
|
192 | The id of the kernel to interrupt. | |
179 | """ |
|
193 | """ | |
180 | km = self.get_kernel(kernel_id) |
|
194 | km = self.get_kernel(kernel_id) | |
181 |
self.stop_ |
|
195 | self.stop_restarter(kernel_id) | |
182 | km.restart_kernel() |
|
196 | km.restart_kernel() | |
183 |
self.start_ |
|
197 | self.start_restarter(kernel_id) | |
184 |
|
198 | |||
185 | def is_alive(self, kernel_id): |
|
199 | def is_alive(self, kernel_id): | |
186 | """Is the kernel alive. |
|
200 | """Is the kernel alive. |
General Comments 0
You need to be logged in to leave comments.
Login now