Skip to content

Commit

Permalink
Quickly create Remote Jupyter Finders (#14121)
Browse files Browse the repository at this point in the history
  • Loading branch information
DonJayamanne authored Aug 15, 2023
1 parent ea43e38 commit e2fefb8
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 12 deletions.
74 changes: 69 additions & 5 deletions src/kernels/jupyter/finder/remoteKernelFinderController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@

import { injectable, inject } from 'inversify';
import { IKernelFinder, IKernelProvider } from '../../types';
import { IDisposableRegistry, IExtensionContext } from '../../../platform/common/types';
import { IDisposableRegistry, IExtensionContext, IFeaturesManager } from '../../../platform/common/types';
import {
IOldJupyterSessionManagerFactory,
IJupyterServerUriStorage,
IJupyterRemoteCachedKernelValidator,
IJupyterServerUriEntry,
IJupyterUriProviderRegistration,
JupyterServerProviderHandle
JupyterServerProviderHandle,
IJupyterServerProviderRegistry
} from '../types';
import { noop } from '../../../platform/common/utils/misc';
import { IApplicationEnvironment } from '../../../platform/common/application/types';
Expand All @@ -22,7 +23,9 @@ import { IFileSystem } from '../../../platform/common/platform/types';
import { ContributedKernelFinderKind } from '../../internalTypes';
import { generateIdFromRemoteProvider } from '../jupyterUtils';
import { swallowExceptions } from '../../../platform/common/utils/decorators';
import { IJupyterUriProvider } from '../../../api';
import { IJupyterUriProvider, JupyterServerCollection, JupyterServerProvider } from '../../../api';
import { CancellationTokenSource } from 'vscode';
import { traceError } from '../../../platform/logging';

@injectable()
export class RemoteKernelFinderController implements IExtensionSyncActivationService {
Expand All @@ -42,7 +45,11 @@ export class RemoteKernelFinderController implements IExtensionSyncActivationSer
@inject(IFileSystem) private readonly fs: IFileSystem,
@inject(IExtensionContext) private readonly context: IExtensionContext,
@inject(IJupyterUriProviderRegistration)
private readonly jupyterPickerRegistration: IJupyterUriProviderRegistration
private readonly jupyterPickerRegistration: IJupyterUriProviderRegistration,
@inject(IJupyterServerProviderRegistry)
private readonly jupyterServerProviderRegistry: IJupyterServerProviderRegistry,
@inject(IFeaturesManager)
private readonly features: IFeaturesManager
) {}
private readonly handledProviders = new WeakSet<IJupyterUriProvider>();
activate() {
Expand All @@ -55,9 +62,10 @@ export class RemoteKernelFinderController implements IExtensionSyncActivationSer

// Also check for when a URI is removed
this.serverUriStorage.onDidRemove(this.urisRemoved, this, this.disposables);

this.jupyterServerProviderRegistry.onDidChangeProviders(this.handleProviderChanges, this, this.disposables);
// Add in the URIs that we already know about
this.buildListOfFinders();
this.handleProviderChanges().catch(noop);
}
private buildListOfFinders() {
// Add in the URIs that we already know about
Expand All @@ -77,6 +85,62 @@ export class RemoteKernelFinderController implements IExtensionSyncActivationSer
});
this.buildListOfFinders();
}
private mappedProviders = new WeakSet<JupyterServerProvider>();
private mappedServers = new Set<string>();
@swallowExceptions('Handle Jupyter Provider Changes')
private async handleProviderChanges() {
if (!this.features.features.enableProposedJupyterServerProviderApi) {
return;
}
const token = new CancellationTokenSource();
this.disposables.push(token);
await Promise.all(
this.jupyterServerProviderRegistry.providers.map(async (collection) => {
const serverProvider = collection.serverProvider;
if (!serverProvider || this.mappedProviders.has(serverProvider)) {
return;
}
this.mappedProviders.add(serverProvider);
if (serverProvider?.onDidChangeServers) {
serverProvider?.onDidChangeServers(
() => this.lookForServersInCollection(collection),
this,
this.disposables
);
}
await this.lookForServersInCollection(collection).catch(noop);
})
);
token.dispose();
}
@swallowExceptions('Check Servers in Jupyter Server Provider')
private async lookForServersInCollection(collection: JupyterServerCollection) {
const serverProvider = collection.serverProvider;
if (!serverProvider) {
return;
}
const token = new CancellationTokenSource();
try {
const servers = await serverProvider.getJupyterServers(token.token);
servers.forEach((server) => {
const serverId = `${collection.extensionId}#${collection.id}#${server.id}`;
if (this.mappedServers.has(serverId)) {
return;
}
this.mappedServers.add(serverId);
const info = {
extensionId: collection.extensionId,
handle: server.id,
id: collection.id
};
this.createRemoteKernelFinder(info, server.label);
});
} catch (ex) {
traceError(`Failed to get servers for Collection ${collection.id} in ${collection.extensionId}`, ex);
} finally {
token.dispose();
}
}
@swallowExceptions('Failed to create a Remote Kernel Finder')
private async validateAndCreateFinder(serverUri: IJupyterServerUriEntry) {
const serverId = generateIdFromRemoteProvider(serverUri.provider);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { IKernelFinder, KernelConnectionMetadata, RemoteKernelConnectionMetadata
import { IApplicationShell } from '../../../platform/common/application/types';
import { InteractiveWindowView, JVSC_EXTENSION_ID, JupyterNotebookView } from '../../../platform/common/constants';
import { disposeAllDisposables } from '../../../platform/common/helpers';
import { IDisposable } from '../../../platform/common/types';
import { IDisposable, IFeaturesManager } from '../../../platform/common/types';
import { Common, DataScience } from '../../../platform/common/utils/localize';
import {
IMultiStepInput,
Expand Down Expand Up @@ -76,7 +76,9 @@ export class RemoteNotebookKernelSourceSelector implements IRemoteNotebookKernel
@inject(IJupyterServerUriStorage) private readonly serverUriStorage: IJupyterServerUriStorage,
@inject(JupyterServerSelector) private readonly serverSelector: JupyterServerSelector,
@inject(JupyterConnection) private readonly jupyterConnection: JupyterConnection,
@inject(IConnectionDisplayDataProvider) private readonly displayDataProvider: IConnectionDisplayDataProvider
@inject(IConnectionDisplayDataProvider) private readonly displayDataProvider: IConnectionDisplayDataProvider,
@inject(IFeaturesManager)
private readonly features: IFeaturesManager
) {}
public async selectRemoteKernel(
notebook: NotebookDocument,
Expand Down Expand Up @@ -135,6 +137,7 @@ export class RemoteNotebookKernelSourceSelector implements IRemoteNotebookKernel
| QuickPickItem
)[] = [];

const displayLastUsedTime = !this.features.features.enableProposedJupyterServerProviderApi;
await Promise.all(
servers
.filter((s) => s.serverProviderHandle.id === provider.id)
Expand All @@ -145,15 +148,18 @@ export class RemoteNotebookKernelSourceSelector implements IRemoteNotebookKernel
generateIdFromRemoteProvider(item.provider) ===
generateIdFromRemoteProvider(server.serverProviderHandle)
);
if (token.isCancellationRequested || !lastUsedTime) {
if ((token.isCancellationRequested || !lastUsedTime) && displayLastUsedTime) {
return;
}
quickPickServerItems.push({
type: KernelFinderEntityQuickPickType.KernelFinder,
kernelFinderInfo: server,
idAndHandle: server.serverProviderHandle,
label: server.displayName,
detail: DataScience.jupyterSelectURIMRUDetail(new Date(lastUsedTime.time)),
detail:
displayLastUsedTime && lastUsedTime?.time
? DataScience.jupyterSelectURIMRUDetail(new Date(lastUsedTime.time))
: undefined,
buttons: provider.removeHandle
? [
{
Expand Down
9 changes: 7 additions & 2 deletions src/platform/common/featureManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ const deprecatedFeatures: DeprecatedFeatureInfo[] = [
export class FeatureManager implements IFeaturesManager {
private _onDidChangeFeatures = new Emitter<void>();
readonly onDidChangeFeatures = this._onDidChangeFeatures.event;
private _features: IFeatureSet = {};
private _features: IFeatureSet = {
enableProposedJupyterServerProviderApi: false
};
get features(): IFeatureSet {
return this._features;
}
Expand All @@ -72,8 +74,11 @@ export class FeatureManager implements IFeaturesManager {
}

private _updateFeatures() {
const enabled = this.workspace
.getConfiguration('jupyter')
.get<boolean>('enableProposedJupyterServerProviderApi', false);
this.features = {
kernelPickerType: 'Insiders'
enableProposedJupyterServerProviderApi: enabled === true
};
}

Expand Down
5 changes: 4 additions & 1 deletion src/platform/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export interface IJupyterSettings {
readonly experiments: IExperiments;
readonly logging: ILoggingSettings;
readonly allowUnauthorizedRemoteConnection: boolean;
readonly enableProposedJupyterServerProviderApi?: boolean;
readonly jupyterInterruptTimeout: number;
readonly jupyterLaunchTimeout: number;
readonly jupyterLaunchRetries: number;
Expand Down Expand Up @@ -257,7 +258,9 @@ export type DeprecatedFeatureInfo = {
setting?: DeprecatedSettingAndValue;
};

export interface IFeatureSet {}
export interface IFeatureSet {
enableProposedJupyterServerProviderApi: boolean;
}

export const IFeaturesManager = Symbol('IFeaturesManager');

Expand Down

0 comments on commit e2fefb8

Please sign in to comment.