diff --git a/packages/services/src/kernel/default.ts b/packages/services/src/kernel/default.ts index d770157cf691..3e1757335eb7 100644 --- a/packages/services/src/kernel/default.ts +++ b/packages/services/src/kernel/default.ts @@ -28,17 +28,13 @@ import { import * as serialize from './serialize'; import * as validate from './validate'; +import { KernelSpec } from '../kernelspec/kernelspec'; /** * The url for the kernel service. */ const KERNEL_SERVICE_URL = 'api/kernels'; -/** - * The url for the kernelspec service. - */ -const KERNELSPEC_SERVICE_URL = 'api/kernelspecs'; - // Stub for requirejs. declare var requirejs: any; @@ -233,11 +229,11 @@ export class DefaultKernel implements Kernel.IKernel { * * @returns A promise that resolves with the kernel spec. */ - getSpec(): Promise { + getSpec(): Promise { if (this._specPromise) { return this._specPromise; } - this._specPromise = Private.findSpecs(this.serverSettings).then(specs => { + this._specPromise = KernelSpec.getSpecs(this.serverSettings).then(specs => { return specs.kernelspecs[this._name]; }); return this._specPromise; @@ -1437,7 +1433,7 @@ export class DefaultKernel implements Kernel.IKernel { } = Object.create(null); private _info = new PromiseDelegate(); private _pendingMessages: KernelMessage.IMessage[] = []; - private _specPromise: Promise; + private _specPromise: Promise; private _statusChanged = new Signal(this); private _connectionStatusChanged = new Signal( this @@ -1481,22 +1477,6 @@ export namespace DefaultKernel { return Private.findById(id, settings); } - /** - * Fetch all of the kernel specs. - * - * @param settings - The optional server settings. - * - * @returns A promise that resolves with the kernel specs. - * - * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernelspecs). - */ - export function getSpecs( - settings?: ServerConnection.ISettings - ): Promise { - return Private.getSpecs(settings); - } - /** * Fetch the running kernels. * @@ -1594,13 +1574,6 @@ namespace Private { */ export const runningKernels: DefaultKernel[] = []; - /** - * A module private store of kernel specs by base url. - */ - export const specs: { - [key: string]: Promise; - } = Object.create(null); - /** * Find a kernel by id. * @@ -1630,45 +1603,6 @@ namespace Private { } } - /** - * Get the cached kernel specs or fetch them. - */ - export function findSpecs( - settings?: ServerConnection.ISettings - ): Promise { - settings = settings || ServerConnection.makeSettings(); - let promise = specs[settings.baseUrl]; - if (promise) { - return promise; - } - return getSpecs(settings); - } - - /** - * Fetch all of the kernel specs. - * - * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernelspecs). - */ - export function getSpecs( - settings?: ServerConnection.ISettings - ): Promise { - settings = settings || ServerConnection.makeSettings(); - let url = URLExt.join(settings.baseUrl, KERNELSPEC_SERVICE_URL); - let promise = ServerConnection.makeRequest(url, {}, settings) - .then(response => { - if (response.status !== 200) { - throw new ServerConnection.ResponseError(response); - } - return response.json(); - }) - .then(data => { - return validate.validateSpecModels(data); - }); - Private.specs[settings.baseUrl] = promise; - return promise; - } - /** * Fetch the running kernels. * diff --git a/packages/services/src/kernel/kernel.ts b/packages/services/src/kernel/kernel.ts index b40f37e13c67..05c7f993d67c 100644 --- a/packages/services/src/kernel/kernel.ts +++ b/packages/services/src/kernel/kernel.ts @@ -15,6 +15,8 @@ import { DefaultKernel } from './default'; import { KernelMessage } from './messages'; +import { KernelSpec } from '../kernelspec'; + /** * A namespace for kernel types, interfaces, and type checker functions. */ @@ -99,7 +101,7 @@ export namespace Kernel { * * @returns A promise that resolves with the kernel spec for this kernel. */ - getSpec(): Promise; + getSpec(): Promise; /** * Send a shell message to the kernel. @@ -520,22 +522,6 @@ export namespace Kernel { return DefaultKernel.findById(id, settings); } - /** - * Fetch all of the kernel specs. - * - * @param settings - The optional server settings. - * - * @returns A promise that resolves with the kernel specs. - * - * #### Notes - * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernelspecs). - */ - export function getSpecs( - settings?: ServerConnection.ISettings - ): Promise { - return DefaultKernel.getSpecs(settings); - } - /** * Fetch the running kernels. * @@ -662,15 +648,11 @@ export namespace Kernel { * Object which manages kernel instances for a given base url. * * #### Notes - * The manager is responsible for maintaining the state of running - * kernels and the initial fetch of kernel specs. + * The manager is responsible for maintaining the state of running kernels + * through polling the server. Use a manager if you want to be notified of + * changes to kernels. */ export interface IManager extends IDisposable { - /** - * A signal emitted when the kernel specs change. - */ - specsChanged: ISignal; - /** * A signal emitted when the running kernels change. */ @@ -687,14 +669,6 @@ export namespace Kernel { */ serverSettings?: ServerConnection.ISettings; - /** - * The kernel spec models. - * - * #### Notes - * The value will be null until the manager is ready. - */ - readonly specs: Kernel.ISpecModels | null; - /** * Whether the manager is ready. */ @@ -712,17 +686,6 @@ export namespace Kernel { */ running(): IIterator; - /** - * Force a refresh of the specs from the server. - * - * @returns A promise that resolves when the specs are fetched. - * - * #### Notes - * This is intended to be called only in response to a user action, - * since the manager maintains its internal state. - */ - refreshSpecs(): Promise; - /** * Force a refresh of the running kernels. * @@ -1049,67 +1012,6 @@ export namespace Kernel { readonly name: string; } - /** - * Kernel Spec interface. - * - * #### Notes - * See [Kernel specs](https://jupyter-client.readthedocs.io/en/latest/kernels.html#kernelspecs). - */ - export interface ISpecModel extends JSONObject { - /** - * The name of the kernel spec. - */ - readonly name: string; - - /** - * The name of the language of the kernel. - */ - readonly language: string; - - /** - * A list of command line arguments used to start the kernel. - */ - readonly argv: string[]; - - /** - * The kernel’s name as it should be displayed in the UI. - */ - readonly display_name: string; - - /** - * A dictionary of environment variables to set for the kernel. - */ - readonly env?: JSONObject; - - /** - * A mapping of resource file name to download path. - */ - readonly resources: { [key: string]: string }; - - /** - * A dictionary of additional attributes about this kernel; used by clients to aid in kernel selection. - */ - readonly metadata?: JSONObject; - } - - /** - * The available kernelSpec models. - * - * #### Notes - * See the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernelspecs). - */ - export interface ISpecModels extends JSONObject { - /** - * The name of the default kernel spec. - */ - default: string; - - /** - * A mapping of kernel spec name to spec. - */ - readonly kernelspecs: { [key: string]: ISpecModel }; - } - /** * Arguments interface for the anyMessage signal. */ diff --git a/packages/services/src/kernel/manager.ts b/packages/services/src/kernel/manager.ts index f01d604f169f..d08e05ece07a 100644 --- a/packages/services/src/kernel/manager.ts +++ b/packages/services/src/kernel/manager.ts @@ -32,15 +32,13 @@ export class KernelManager implements Kernel.IManager { options.serverSettings || ServerConnection.makeSettings(); // Initialize internal data. - this._ready = Promise.all([this.requestRunning(), this.requestSpecs()]) - .then(_ => undefined) - .catch(_ => undefined) - .then(() => { - if (this.isDisposed) { - return; - } - this._isReady = true; - }); + this._ready = (async () => { + await this.requestRunning(); + if (this.isDisposed) { + return; + } + this._isReady = true; + })(); // Start model and specs polling with exponential backoff. this._pollModels = new Poll({ @@ -54,20 +52,8 @@ export class KernelManager implements Kernel.IManager { name: `@jupyterlab/services:KernelManager#models`, standby: options.standby || 'when-hidden' }); - this._pollSpecs = new Poll({ - auto: false, - factory: () => this.requestSpecs(), - frequency: { - interval: 61 * 1000, - backoff: true, - max: 300 * 1000 - }, - name: `@jupyterlab/services:KernelManager#specs`, - standby: options.standby || 'when-hidden' - }); void this.ready.then(() => { void this._pollModels.start(); - void this._pollSpecs.start(); }); } @@ -77,7 +63,7 @@ export class KernelManager implements Kernel.IManager { readonly serverSettings: ServerConnection.ISettings; /** - * Test whether the terminal manager is disposed. + * Test whether the kernel manager is disposed. */ get isDisposed(): boolean { return this._isDisposed; @@ -104,20 +90,6 @@ export class KernelManager implements Kernel.IManager { return this._runningChanged; } - /** - * Get the most recently fetched kernel specs. - */ - get specs(): Kernel.ISpecModels | null { - return this._specs; - } - - /** - * A signal emitted when the specs change. - */ - get specsChanged(): ISignal { - return this._specsChanged; - } - /** * A signal emitted when there is a connection failure. */ @@ -148,7 +120,6 @@ export class KernelManager implements Kernel.IManager { this._isDisposed = true; this._models.length = 0; this._pollModels.dispose(); - this._pollSpecs.dispose(); Signal.clearData(this); } @@ -177,20 +148,6 @@ export class KernelManager implements Kernel.IManager { await this._pollModels.tick; } - /** - * Force a refresh of the specs from the server. - * - * @returns A promise that resolves when the specs are fetched. - * - * #### Notes - * This is intended to be called only in response to a user action, - * since the manager maintains its internal state. - */ - async refreshSpecs(): Promise { - await this._pollSpecs.refresh(); - await this._pollSpecs.tick; - } - /** * Create an iterator over the most recent running kernels. * @@ -313,20 +270,6 @@ export class KernelManager implements Kernel.IManager { } } - /** - * Execute a request to the server to poll specs and update state. - */ - protected async requestSpecs(): Promise { - const specs = await Kernel.getSpecs(this.serverSettings); - if (this._isDisposed) { - return; - } - if (!JSONExt.deepEqual(specs, this._specs)) { - this._specs = specs; - this._specsChanged.emit(specs); - } - } - /** * Handle a kernel starting. */ @@ -359,11 +302,8 @@ export class KernelManager implements Kernel.IManager { private _kernels = new Set(); private _models: Kernel.IModel[] = []; private _pollModels: Poll; - private _pollSpecs: Poll; private _ready: Promise; private _runningChanged = new Signal(this); - private _specs: Kernel.ISpecModels | null = null; - private _specsChanged = new Signal(this); private _connectionFailure = new Signal(this); } diff --git a/packages/services/src/kernel/validate.ts b/packages/services/src/kernel/validate.ts index 18d16b8da9ec..a459b205e0be 100644 --- a/packages/services/src/kernel/validate.ts +++ b/packages/services/src/kernel/validate.ts @@ -38,7 +38,6 @@ const IOPUB_CONTENT_FIELDS: { [key: string]: any } = { shutdown_reply: { restart: 'boolean' } // Emitted by the IPython kernel. }; - /** * Validate the header of a kernel message. */ @@ -90,4 +89,3 @@ export function validateModel(model: Kernel.IModel): void { validateProperty(model, 'name', 'string'); validateProperty(model, 'id', 'string'); } - diff --git a/packages/services/src/kernelspec/default.ts b/packages/services/src/kernelspec/default.ts new file mode 100644 index 000000000000..7fbbfc4ff81f --- /dev/null +++ b/packages/services/src/kernelspec/default.ts @@ -0,0 +1,68 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { KernelSpec } from './kernelspec'; +import { ServerConnection } from '../serverconnection'; +import { URLExt } from '@jupyterlab/coreutils'; +import { validateSpecModels } from './validate'; + +/** + * The url for the kernelspec service. + */ +const KERNELSPEC_SERVICE_URL = 'api/kernelspecs'; + +export namespace DefaultKernelSpec { + /** + * Fetch all of the kernel specs. + * + * @param settings - The optional server settings. + * @param useCache - Whether to use the cache. If false, always request. + * + * @returns A promise that resolves with the kernel specs. + * + * #### Notes + * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernelspecs). + */ + export function getSpecs( + settings?: ServerConnection.ISettings, + useCache = true + ): Promise { + settings = settings || ServerConnection.makeSettings(); + if (useCache && Private.specs[settings.baseUrl]) { + return Private.specs[settings.baseUrl]; + } + + let url = URLExt.join(settings.baseUrl, KERNELSPEC_SERVICE_URL); + let promise = Private.requestSpecs(url, settings); + Private.specs[settings.baseUrl] = promise; + return promise; + } +} + +namespace Private { + /** + * A module private store of kernel specs by base url. + */ + export const specs: { + [key: string]: Promise; + } = Object.create(null); + + /** + * Fetch all of the kernel specs. + * + * #### Notes + * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernelspecs). + */ + + export async function requestSpecs( + url: string, + settings: ServerConnection.ISettings + ): Promise { + const response = await ServerConnection.makeRequest(url, {}, settings); + if (response.status !== 200) { + throw new ServerConnection.ResponseError(response); + } + const data = await response.json(); + return validateSpecModels(data); + } +} diff --git a/packages/services/src/kernelspec/index.ts b/packages/services/src/kernelspec/index.ts new file mode 100644 index 000000000000..36f94d6f3e3d --- /dev/null +++ b/packages/services/src/kernelspec/index.ts @@ -0,0 +1,6 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. +'use strict'; + +export * from './kernelspec'; +export * from './manager'; diff --git a/packages/services/src/kernelspec/kernelspec.ts b/packages/services/src/kernelspec/kernelspec.ts new file mode 100644 index 000000000000..f255d5d0b4df --- /dev/null +++ b/packages/services/src/kernelspec/kernelspec.ts @@ -0,0 +1,140 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { JSONObject } from '@phosphor/coreutils'; +import { ServerConnection } from '..'; +import { DefaultKernelSpec } from './default'; +import { ISignal } from '@phosphor/signaling'; +import { IDisposable } from '@phosphor/disposable'; + +export namespace KernelSpec { + /** + * Kernel Spec interface. + * + * #### Notes + * See [Kernel specs](https://jupyter-client.readthedocs.io/en/latest/kernels.html#kernelspecs). + */ + export interface ISpecModel extends JSONObject { + /** + * The name of the kernel spec. + */ + readonly name: string; + + /** + * The name of the language of the kernel. + */ + readonly language: string; + + /** + * A list of command line arguments used to start the kernel. + */ + readonly argv: string[]; + + /** + * The kernel’s name as it should be displayed in the UI. + */ + readonly display_name: string; + + /** + * A dictionary of environment variables to set for the kernel. + */ + readonly env?: JSONObject; + + /** + * A mapping of resource file name to download path. + */ + readonly resources: { [key: string]: string }; + + /** + * A dictionary of additional attributes about this kernel; used by clients to aid in kernel selection. + */ + readonly metadata?: JSONObject; + } + + /** + * The available kernelSpec models. + * + * #### Notes + * See the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernelspecs). + */ + export interface ISpecModels extends JSONObject { + /** + * The name of the default kernel spec. + */ + default: string; + + /** + * A mapping of kernel spec name to spec. + */ + readonly kernelspecs: { [key: string]: ISpecModel }; + } + + /** + * Fetch all of the kernel specs. + * + * @param settings - The optional server settings. + * + * @returns A promise that resolves with the kernel specs. + * + * #### Notes + * Uses the [Jupyter Notebook API](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml#!/kernelspecs). + */ + export function getSpecs( + settings?: ServerConnection.ISettings + ): Promise { + return DefaultKernelSpec.getSpecs(settings); + } + + /** + * Object which manages kernel instances for a given base url. + * + * #### Notes + * The manager is responsible for maintaining the state of kernel specs. + */ + export interface IManager extends IDisposable { + /** + * A signal emitted when the kernel specs change. + */ + specsChanged: ISignal; + + /** + * A signal emitted when there is a connection failure. + * TODO: figure out the relationship between this and the other connection status signals for kernels. + */ + connectionFailure: ISignal; + + /** + * The server settings for the manager. + */ + serverSettings?: ServerConnection.ISettings; + + /** + * The kernel spec models. + * + * #### Notes + * The value will be null until the manager is ready. + */ + readonly specs: ISpecModels | null; + + /** + * Whether the manager is ready. + */ + readonly isReady: boolean; + + /** + * A promise that resolves when the manager is initially ready. + */ + readonly ready: Promise; + + /** + * Force a refresh of the specs from the server. + * + * @returns A promise that resolves when the specs are fetched. + * + * #### Notes + * This is intended to be called only in response to a user action, + * since the manager maintains its internal state. + */ + refreshSpecs(): Promise; + } +} diff --git a/packages/services/src/kernelspec/manager.ts b/packages/services/src/kernelspec/manager.ts new file mode 100644 index 000000000000..f270d8f7971b --- /dev/null +++ b/packages/services/src/kernelspec/manager.ts @@ -0,0 +1,165 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +import { Poll } from '@jupyterlab/coreutils'; +import { ServerConnection } from '../serverconnection'; +import { KernelSpec } from './kernelspec'; +import { ISignal, Signal } from '@phosphor/signaling'; +import { JSONExt } from '@phosphor/coreutils'; +/** + * An implementation of a kernel manager. + */ +export class KernelSpecManager implements KernelSpec.IManager { + /** + * Construct a new kernel manager. + * + * @param options - The default options for kernel. + */ + constructor(options: KernelSpecManager.IOptions = {}) { + this.serverSettings = + options.serverSettings || ServerConnection.makeSettings(); + + // Initialize internal data. + this._ready = Promise.all([this.requestSpecs()]) + .then(_ => undefined) + .catch(_ => undefined) + .then(() => { + if (this.isDisposed) { + return; + } + this._isReady = true; + }); + + this._pollSpecs = new Poll({ + auto: false, + factory: () => this.requestSpecs(), + frequency: { + interval: 61 * 1000, + backoff: true, + max: 300 * 1000 + }, + name: `@jupyterlab/services:KernelSpecManager#specs`, + standby: options.standby || 'when-hidden' + }); + void this.ready.then(() => { + void this._pollSpecs.start(); + }); + } + + /** + * The server settings for the manager. + */ + readonly serverSettings: ServerConnection.ISettings; + + /** + * Test whether the kernel manager is disposed. + */ + get isDisposed(): boolean { + return this._isDisposed; + } + + /** + * Test whether the manager is ready. + */ + get isReady(): boolean { + return this._isReady; + } + + /** + * A promise that fulfills when the manager is ready. + */ + get ready(): Promise { + return this._ready; + } + + /** + * Get the most recently fetched kernel specs. + */ + get specs(): KernelSpec.ISpecModels | null { + return this._specs; + } + + /** + * A signal emitted when the specs change. + */ + get specsChanged(): ISignal { + return this._specsChanged; + } + + /** + * A signal emitted when there is a connection failure. + */ + get connectionFailure(): ISignal { + return this._connectionFailure; + } + + /** + * Dispose of the resources used by the manager. + */ + dispose(): void { + if (this._isDisposed) { + return; + } + this._isDisposed = true; + this._pollSpecs.dispose(); + Signal.clearData(this); + } + + /** + * Force a refresh of the specs from the server. + * + * @returns A promise that resolves when the specs are fetched. + * + * #### Notes + * This is intended to be called only in response to a user action, + * since the manager maintains its internal state. + */ + async refreshSpecs(): Promise { + await this._pollSpecs.refresh(); + await this._pollSpecs.tick; + } + + /** + * Execute a request to the server to poll specs and update state. + */ + protected async requestSpecs(): Promise { + const specs = await KernelSpec.getSpecs(this.serverSettings); + if (this._isDisposed) { + return; + } + if (!JSONExt.deepEqual(specs, this._specs)) { + this._specs = specs; + this._specsChanged.emit(specs); + } + } + + private _isDisposed = false; + private _isReady = false; + private _connectionFailure = new Signal(this); + + private _pollSpecs: Poll; + private _ready: Promise; + + private _specs: KernelSpec.ISpecModels | null = null; + private _specsChanged = new Signal(this); +} + +/** + * The namespace for `KernelManager` class statics. + */ +export namespace KernelSpecManager { + /** + * The options used to initialize a KernelManager. + */ + export interface IOptions { + /** + * The server settings for the manager. + */ + serverSettings?: ServerConnection.ISettings; + + /** + * When the manager stops polling the API. Defaults to `when-hidden`. + */ + standby?: Poll.Standby; + } +} diff --git a/packages/services/src/kernelspec/validate.ts b/packages/services/src/kernelspec/validate.ts new file mode 100644 index 000000000000..24b2c6f31753 --- /dev/null +++ b/packages/services/src/kernelspec/validate.ts @@ -0,0 +1,78 @@ +import { KernelSpec } from './kernelspec'; +import { validateProperty } from '../validate'; + +/** + * Validate a server kernelspec model to a client side model. + */ +export function validateSpecModel(data: any): KernelSpec.ISpecModel { + let spec = data.spec; + if (!spec) { + throw new Error('Invalid kernel spec'); + } + validateProperty(data, 'name', 'string'); + validateProperty(data, 'resources', 'object'); + validateProperty(spec, 'language', 'string'); + validateProperty(spec, 'display_name', 'string'); + validateProperty(spec, 'argv', 'array'); + + let metadata: any = null; + if (spec.hasOwnProperty('metadata')) { + validateProperty(spec, 'metadata', 'object'); + metadata = spec.metadata; + } + + let env: any = null; + if (spec.hasOwnProperty('env')) { + validateProperty(spec, 'env', 'object'); + env = spec.env; + } + return { + name: data.name, + resources: data.resources, + language: spec.language, + display_name: spec.display_name, + argv: spec.argv, + metadata, + env + }; +} + +/** + * Validate a `Kernel.ISpecModels` object. + */ +export function validateSpecModels(data: any): KernelSpec.ISpecModels { + if (!data.hasOwnProperty('kernelspecs')) { + throw new Error('No kernelspecs found'); + } + let keys = Object.keys(data.kernelspecs); + let kernelspecs: { [key: string]: KernelSpec.ISpecModel } = Object.create( + null + ); + let defaultSpec = data.default; + + for (let i = 0; i < keys.length; i++) { + let ks = data.kernelspecs[keys[i]]; + try { + kernelspecs[keys[i]] = validateSpecModel(ks); + } catch (err) { + // Remove the errant kernel spec. + console.warn(`Removing errant kernel spec: ${keys[i]}`); + } + } + keys = Object.keys(kernelspecs); + if (!keys.length) { + throw new Error('No valid kernelspecs found'); + } + if ( + !defaultSpec || + typeof defaultSpec !== 'string' || + !(defaultSpec in kernelspecs) + ) { + defaultSpec = keys[0]; + console.warn(`Default kernel not found, using '${keys[0]}'`); + } + return { + default: defaultSpec, + kernelspecs + }; +} diff --git a/packages/services/src/manager.ts b/packages/services/src/manager.ts index 111e092313f6..960c736c30c1 100644 --- a/packages/services/src/manager.ts +++ b/packages/services/src/manager.ts @@ -15,6 +15,8 @@ import { Contents, ContentsManager } from './contents'; import { Kernel } from './kernel'; +import { KernelSpec, KernelSpecManager } from './kernelspec'; + import { Session, SessionManager } from './session'; import { Setting, SettingManager } from './setting'; @@ -47,10 +49,7 @@ export class ServiceManager implements ServiceManager.IManager { this.builder = new BuildManager(normalized); this.workspaces = new WorkspaceManager(normalized); this.nbconvert = new NbConvertManager(normalized); - - this.sessions.specsChanged.connect((_, specs) => { - this._specsChanged.emit(specs); - }); + this.kernelspecs = new KernelSpecManager(normalized); // Relay connection failures from the service managers that poll // the server for running sessions. @@ -68,13 +67,6 @@ export class ServiceManager implements ServiceManager.IManager { }); } - /** - * A signal emitted when the kernel specs change. - */ - get specsChanged(): ISignal { - return this._specsChanged; - } - /** * A signal emitted when there is a connection failure with the kernel. */ @@ -105,13 +97,6 @@ export class ServiceManager implements ServiceManager.IManager { this.terminals.dispose(); } - /** - * The kernel spec models. - */ - get specs(): Kernel.ISpecModels | null { - return this.sessions.specs; - } - /** * The server settings of the manager. */ @@ -122,6 +107,11 @@ export class ServiceManager implements ServiceManager.IManager { */ readonly sessions: SessionManager; + /** + * Get the session manager instance. + */ + readonly kernelspecs: KernelSpecManager; + /** * Get the setting manager instance. */ @@ -172,7 +162,6 @@ export class ServiceManager implements ServiceManager.IManager { private _isDisposed = false; private _readyPromise: Promise; - private _specsChanged = new Signal(this); private _connectionFailure = new Signal(this); private _isReady = false; } @@ -216,19 +205,14 @@ export namespace ServiceManager { readonly sessions: Session.IManager; /** - * The setting manager for the manager. - */ - readonly settings: Setting.IManager; - - /** - * The kernel spec models. + * The session manager for the manager. */ - readonly specs: Kernel.ISpecModels | null; + readonly kernelspecs: KernelSpec.IManager; /** - * A signal emitted when the kernel specs change. + * The setting manager for the manager. */ - readonly specsChanged: ISignal; + readonly settings: Setting.IManager; /** * The terminals manager for the manager. diff --git a/packages/services/src/session/manager.ts b/packages/services/src/session/manager.ts index 4b187fa23ce6..cf0c1d60521d 100644 --- a/packages/services/src/session/manager.ts +++ b/packages/services/src/session/manager.ts @@ -9,8 +9,6 @@ import { JSONExt } from '@phosphor/coreutils'; import { ISignal, Signal } from '@phosphor/signaling'; -import { Kernel } from '../kernel'; - import { ServerConnection } from '../serverconnection'; import { Session } from './session'; @@ -41,13 +39,13 @@ export class SessionManager implements Session.IManager { // Initialize internal data. this._ready = (async () => { - await Promise.all([this.requestRunning(), this.requestSpecs()]); + await this.requestRunning(); if (!this.isDisposed) { this._isReady = true; } })(); - // Start model and specs polling with exponential backoff. + // Start model polling with exponential backoff. this._pollModels = new Poll({ auto: false, factory: () => this.requestRunning(), @@ -59,30 +57,11 @@ export class SessionManager implements Session.IManager { name: `@jupyterlab/services:SessionManager#models`, standby: options.standby || 'when-hidden' }); - this._pollSpecs = new Poll({ - auto: false, - factory: () => this.requestSpecs(), - frequency: { - interval: 61 * 1000, - backoff: true, - max: 300 * 1000 - }, - name: `@jupyterlab/services:SessionManager#specs`, - standby: options.standby || 'when-hidden' - }); void this.ready.then(() => { void this._pollModels.start(); - void this._pollSpecs.start(); }); } - /** - * A signal emitted when the kernel specs change. - */ - get specsChanged(): ISignal { - return this._specsChanged; - } - /** * A signal emitted when the running sessions change. */ @@ -109,13 +88,6 @@ export class SessionManager implements Session.IManager { */ readonly serverSettings: ServerConnection.ISettings; - /** - * Get the most recently fetched kernel specs. - */ - get specs(): Kernel.ISpecModels | null { - return this._specs; - } - /** * Test whether the manager is ready. */ @@ -140,7 +112,6 @@ export class SessionManager implements Session.IManager { this._isDisposed = true; this._models.length = 0; this._pollModels.dispose(); - this._pollSpecs.dispose(); Signal.clearData(this); } @@ -153,20 +124,6 @@ export class SessionManager implements Session.IManager { return iter(this._models); } - /** - * Force a refresh of the specs from the server. - * - * @returns A promise that resolves when the specs are fetched. - * - * #### Notes - * This is intended to be called only in response to a user action, - * since the manager maintains its internal state. - */ - async refreshSpecs(): Promise { - await this._pollSpecs.refresh(); - await this._pollSpecs.tick; - } - /** * Force a refresh of the running sessions. * @@ -325,20 +282,6 @@ export class SessionManager implements Session.IManager { } } - /** - * Execute a request to the server to poll specs and update state. - */ - protected async requestSpecs(): Promise { - const specs = await Kernel.getSpecs(this.serverSettings); - if (this.isDisposed) { - return; - } - if (!JSONExt.deepEqual(specs, this._specs)) { - this._specs = specs; - this._specsChanged.emit(specs); - } - } - /** * Handle a session terminating. */ @@ -397,13 +340,10 @@ export class SessionManager implements Session.IManager { private _isReady = false; private _models: Session.IModel[] = []; private _pollModels: Poll; - private _pollSpecs: Poll; private _ready: Promise; private _runningChanged = new Signal(this); private _connectionFailure = new Signal(this); private _sessions = new Set(); - private _specs: Kernel.ISpecModels | null = null; - private _specsChanged = new Signal(this); } /** diff --git a/packages/services/src/session/session.ts b/packages/services/src/session/session.ts index 1373e5ac4525..4d540339aef2 100644 --- a/packages/services/src/session/session.ts +++ b/packages/services/src/session/session.ts @@ -367,14 +367,9 @@ export namespace Session { * * #### Notes * The manager is responsible for maintaining the state of running - * sessions and the initial fetch of kernel specs. + * sessions. */ export interface IManager extends IDisposable { - /** - * A signal emitted when the kernel specs change. - */ - specsChanged: ISignal; - /** * A signal emitted when the running sessions change. */ @@ -390,14 +385,6 @@ export namespace Session { */ serverSettings?: ServerConnection.ISettings; - /** - * The cached kernel specs. - * - * #### Notes - * This value will be null until the manager is ready. - */ - readonly specs: Kernel.ISpecModels | null; - /** * Test whether the manager is ready. */ @@ -472,17 +459,6 @@ export namespace Session { */ shutdownAll(): Promise; - /** - * Force a refresh of the specs from the server. - * - * @returns A promise that resolves when the specs are fetched. - * - * #### Notes - * This is intended to be called only in response to a user action, - * since the manager maintains its internal state. - */ - refreshSpecs(): Promise; - /** * Force a refresh of the running sessions. *