UNPKG

9.24 kBJavaScriptView Raw
1"use strict";
2// Copyright (c) Jupyter Development Team.
3// Distributed under the terms of the Modified BSD License.
4Object.defineProperty(exports, "__esModule", { value: true });
5exports.KernelManager = void 0;
6const algorithm_1 = require("@lumino/algorithm");
7const polling_1 = require("@lumino/polling");
8const signaling_1 = require("@lumino/signaling");
9const __1 = require("..");
10const basemanager_1 = require("../basemanager");
11const restapi_1 = require("./restapi");
12const default_1 = require("./default");
13/**
14 * An implementation of a kernel manager.
15 */
16class KernelManager extends basemanager_1.BaseManager {
17 /**
18 * Construct a new kernel manager.
19 *
20 * @param options - The default options for kernel.
21 */
22 constructor(options = {}) {
23 var _a;
24 super(options);
25 this._isReady = false;
26 this._kernelConnections = new Set();
27 this._models = new Map();
28 this._runningChanged = new signaling_1.Signal(this);
29 this._connectionFailure = new signaling_1.Signal(this);
30 // Start model and specs polling with exponential backoff.
31 this._pollModels = new polling_1.Poll({
32 auto: false,
33 factory: () => this.requestRunning(),
34 frequency: {
35 interval: 10 * 1000,
36 backoff: true,
37 max: 300 * 1000
38 },
39 name: `@jupyterlab/services:KernelManager#models`,
40 standby: (_a = options.standby) !== null && _a !== void 0 ? _a : 'when-hidden'
41 });
42 // Initialize internal data.
43 this._ready = (async () => {
44 await this._pollModels.start();
45 await this._pollModels.tick;
46 this._isReady = true;
47 })();
48 }
49 /**
50 * Test whether the manager is ready.
51 */
52 get isReady() {
53 return this._isReady;
54 }
55 /**
56 * A promise that fulfills when the manager is ready.
57 */
58 get ready() {
59 return this._ready;
60 }
61 /**
62 * A signal emitted when the running kernels change.
63 */
64 get runningChanged() {
65 return this._runningChanged;
66 }
67 /**
68 * A signal emitted when there is a connection failure.
69 */
70 get connectionFailure() {
71 return this._connectionFailure;
72 }
73 /**
74 * Dispose of the resources used by the manager.
75 */
76 dispose() {
77 if (this.isDisposed) {
78 return;
79 }
80 this._models.clear();
81 this._kernelConnections.forEach(x => x.dispose());
82 this._pollModels.dispose();
83 super.dispose();
84 }
85 /**
86 * Connect to an existing kernel.
87 *
88 * @returns The new kernel connection.
89 *
90 * #### Notes
91 * This will use the manager's server settings and ignore any server
92 * settings passed in the options.
93 */
94 connectTo(options) {
95 var _a;
96 const { id } = options.model;
97 let handleComms = (_a = options.handleComms) !== null && _a !== void 0 ? _a : true;
98 // By default, handle comms only if no other kernel connection is.
99 if (options.handleComms === undefined) {
100 for (const kc of this._kernelConnections) {
101 if (kc.id === id && kc.handleComms) {
102 handleComms = false;
103 break;
104 }
105 }
106 }
107 const kernelConnection = new default_1.KernelConnection(Object.assign(Object.assign({ handleComms }, options), { serverSettings: this.serverSettings }));
108 this._onStarted(kernelConnection);
109 if (!this._models.has(id)) {
110 // We trust the user to connect to an existing kernel, but we verify
111 // asynchronously.
112 void this.refreshRunning().catch(() => {
113 /* no-op */
114 });
115 }
116 return kernelConnection;
117 }
118 /**
119 * Create an iterator over the most recent running kernels.
120 *
121 * @returns A new iterator over the running kernels.
122 */
123 running() {
124 return algorithm_1.iter([...this._models.values()]);
125 }
126 /**
127 * Force a refresh of the running kernels.
128 *
129 * @returns A promise that resolves when the running list has been refreshed.
130 *
131 * #### Notes
132 * This is not typically meant to be called by the user, since the
133 * manager maintains its own internal state.
134 */
135 async refreshRunning() {
136 await this._pollModels.refresh();
137 await this._pollModels.tick;
138 }
139 /**
140 * Start a new kernel.
141 *
142 * @param createOptions - The kernel creation options
143 *
144 * @param connectOptions - The kernel connection options
145 *
146 * @returns A promise that resolves with the kernel connection.
147 *
148 * #### Notes
149 * The manager `serverSettings` will be always be used.
150 */
151 async startNew(createOptions = {}, connectOptions = {}) {
152 const model = await restapi_1.startNew(createOptions, this.serverSettings);
153 return this.connectTo(Object.assign(Object.assign({}, connectOptions), { model }));
154 }
155 /**
156 * Shut down a kernel by id.
157 *
158 * @param id - The id of the target kernel.
159 *
160 * @returns A promise that resolves when the operation is complete.
161 */
162 async shutdown(id) {
163 await restapi_1.shutdownKernel(id, this.serverSettings);
164 await this.refreshRunning();
165 }
166 /**
167 * Shut down all kernels.
168 *
169 * @returns A promise that resolves when all of the kernels are shut down.
170 */
171 async shutdownAll() {
172 // Update the list of models to make sure our list is current.
173 await this.refreshRunning();
174 // Shut down all models.
175 await Promise.all([...this._models.keys()].map(id => restapi_1.shutdownKernel(id, this.serverSettings)));
176 // Update the list of models to clear out our state.
177 await this.refreshRunning();
178 }
179 /**
180 * Find a kernel by id.
181 *
182 * @param id - The id of the target kernel.
183 *
184 * @returns A promise that resolves with the kernel's model.
185 */
186 async findById(id) {
187 if (this._models.has(id)) {
188 return this._models.get(id);
189 }
190 await this.refreshRunning();
191 return this._models.get(id);
192 }
193 /**
194 * Execute a request to the server to poll running kernels and update state.
195 */
196 async requestRunning() {
197 var _a, _b;
198 let models;
199 try {
200 models = await restapi_1.listRunning(this.serverSettings);
201 }
202 catch (err) {
203 // Handle network errors, as well as cases where we are on a
204 // JupyterHub and the server is not running. JupyterHub returns a
205 // 503 (<2.0) or 424 (>2.0) in that case.
206 if (err instanceof __1.ServerConnection.NetworkError ||
207 ((_a = err.response) === null || _a === void 0 ? void 0 : _a.status) === 503 ||
208 ((_b = err.response) === null || _b === void 0 ? void 0 : _b.status) === 424) {
209 this._connectionFailure.emit(err);
210 }
211 throw err;
212 }
213 if (this.isDisposed) {
214 return;
215 }
216 if (this._models.size === models.length &&
217 algorithm_1.every(models, x => {
218 const existing = this._models.get(x.id);
219 if (!existing) {
220 return false;
221 }
222 return existing.name === x.name;
223 })) {
224 // Identical models list (presuming models does not contain duplicate
225 // ids), so just return
226 return;
227 }
228 this._models = new Map(models.map(x => [x.id, x]));
229 // For any kernel connection to a kernel that doesn't exist, notify it of
230 // the shutdown.
231 this._kernelConnections.forEach(kc => {
232 if (!this._models.has(kc.id)) {
233 kc.handleShutdown();
234 }
235 });
236 this._runningChanged.emit(models);
237 }
238 /**
239 * Handle a kernel starting.
240 */
241 _onStarted(kernelConnection) {
242 this._kernelConnections.add(kernelConnection);
243 kernelConnection.statusChanged.connect(this._onStatusChanged, this);
244 kernelConnection.disposed.connect(this._onDisposed, this);
245 }
246 _onDisposed(kernelConnection) {
247 this._kernelConnections.delete(kernelConnection);
248 // A dispose emission could mean the server session is deleted, or that
249 // the kernel JS object is disposed and the kernel still exists on the
250 // server, so we refresh from the server to make sure we reflect the
251 // server state.
252 void this.refreshRunning().catch(() => {
253 /* no-op */
254 });
255 }
256 _onStatusChanged(kernelConnection, status) {
257 if (status === 'dead') {
258 // We asynchronously update our list of kernels, which asynchronously
259 // will dispose them. We do not want to immediately dispose them because
260 // there may be other signal handlers that want to be called.
261 void this.refreshRunning().catch(() => {
262 /* no-op */
263 });
264 }
265 }
266}
267exports.KernelManager = KernelManager;
268//# sourceMappingURL=manager.js.map
\No newline at end of file