Skip to content

Commit 30f43b7

Browse files
committed
Working but super slow
1 parent 55ac090 commit 30f43b7

File tree

14 files changed

+150
-89
lines changed

14 files changed

+150
-89
lines changed

package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@
136136
"DataScience.startingJupyter": "Starting Jupyter server",
137137
"DataScience.connectingToJupyter": "Connecting to Jupyter server",
138138
"DataScience.connectingToIPyKernel": "Connecting to IPython kernel",
139+
"DataScience.connectedToIPyKernel": "Connected.",
139140
"Experiments.inGroup": "User belongs to experiment group '{0}'",
140141
"Interpreters.RefreshingInterpreters": "Refreshing Python Interpreters",
141142
"Interpreters.entireWorkspace": "Entire workspace",

src/client/common/utils/localize.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ export namespace DataScience {
377377
export const importingFormat = localize('DataScience.importingFormat', 'Importing {0}');
378378
export const startingJupyter = localize('DataScience.startingJupyter', 'Starting Jupyter server');
379379
export const connectingIPyKernel = localize('DataScience.connectingToIPyKernel', 'Connecting to IPython kernel');
380+
export const connectedToIPyKernel = localize('DataScience.connectedToIPyKernel', 'Connected.');
380381
export const connectingToJupyter = localize('DataScience.connectingToJupyter', 'Connecting to Jupyter server');
381382
export const exportingFormat = localize('DataScience.exportingFormat', 'Exporting {0}');
382383
export const runAllCellsLensCommandTitle = localize(

src/client/datascience/baseJupyterSession.ts

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,6 @@ export abstract class BaseJupyterSession implements IJupyterSession {
4040
protected get session(): ISessionWithSocket | undefined {
4141
return this._session;
4242
}
43-
protected set session(session: ISessionWithSocket | undefined) {
44-
const oldSession = this._session;
45-
this._session = session;
46-
47-
// If we have a new session, then emit the new kernel connection information.
48-
if (session && oldSession !== session) {
49-
if (!session.kernelSocketInformation) {
50-
traceError(`Unable to find WebSocket connetion assocated with kerne ${session.kernel.id}`);
51-
this._kernelSocket.next(undefined);
52-
} else {
53-
this._kernelSocket.next({
54-
options: {
55-
clientId: session.kernel.clientId,
56-
id: session.kernel.id,
57-
model: { ...session.kernel.model },
58-
userName: session.kernel.username
59-
},
60-
socket: session.kernelSocketInformation.socket
61-
});
62-
}
63-
}
64-
}
6543
protected kernelSpec: IJupyterKernelSpec | LiveKernelModel | undefined;
6644
public get kernelSocket(): Observable<KernelSocketInformation | undefined> {
6745
return this._kernelSocket;
@@ -119,7 +97,7 @@ export abstract class BaseJupyterSession implements IJupyterSession {
11997
} catch {
12098
noop();
12199
}
122-
this.session = undefined;
100+
this.setSession(undefined);
123101
this.restartSessionPromise = undefined;
124102
}
125103
if (this.onStatusChangedEvent) {
@@ -160,13 +138,13 @@ export abstract class BaseJupyterSession implements IJupyterSession {
160138
this.kernelSpec = kernel;
161139

162140
// Save the new session
163-
this.session = newSession;
141+
this.setSession(newSession);
164142

165143
// Listen for session status changes
166144
this.session?.statusChanged.connect(this.statusHandler); // NOSONAR
167145

168146
// Start the restart session promise too.
169-
this.restartSessionPromise = this.createRestartSession(kernel, this.session);
147+
this.restartSessionPromise = this.createRestartSession(kernel, newSession);
170148
}
171149

172150
public async restart(_timeout: number): Promise<void> {
@@ -189,7 +167,7 @@ export abstract class BaseJupyterSession implements IJupyterSession {
189167
const oldStatusHandler = this.statusHandler;
190168

191169
// Just switch to the other session. It should already be ready
192-
this.session = await this.restartSessionPromise;
170+
this.setSession(await this.restartSessionPromise);
193171
if (!this.session) {
194172
throw new Error(localize.DataScience.sessionDisposed());
195173
}
@@ -329,6 +307,29 @@ export abstract class BaseJupyterSession implements IJupyterSession {
329307
timeoutMS: number
330308
): Promise<ISessionWithSocket>;
331309

310+
// Changes the current session.
311+
protected setSession(session: ISessionWithSocket | undefined) {
312+
const oldSession = this._session;
313+
this._session = session;
314+
315+
// If we have a new session, then emit the new kernel connection information.
316+
if (session && oldSession !== session) {
317+
if (!session.kernelSocketInformation) {
318+
traceError(`Unable to find WebSocket connection assocated with kerne ${session.kernel.id}`);
319+
this._kernelSocket.next(undefined);
320+
} else {
321+
this._kernelSocket.next({
322+
options: {
323+
clientId: session.kernel.clientId,
324+
id: session.kernel.id,
325+
model: { ...session.kernel.model },
326+
userName: session.kernel.username
327+
},
328+
socket: session.kernelSocketInformation.socket
329+
});
330+
}
331+
}
332+
}
332333
protected async shutdownSession(
333334
session: ISessionWithSocket | undefined,
334335
statusHandler: Slot<ISessionWithSocket, Kernel.Status> | undefined

src/client/datascience/jupyter/jupyterSession.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,8 @@ export class JupyterSession extends BaseJupyterSession {
9090
}
9191

9292
// Start a new session
93-
this.session = await this.createSession(
94-
this.serverSettings,
95-
this.kernelSpec,
96-
this.contentsManager,
97-
cancelToken
93+
this.setSession(
94+
await this.createSession(this.serverSettings, this.kernelSpec, this.contentsManager, cancelToken)
9895
);
9996

10097
// Listen for session status changes

src/client/datascience/kernel-launcher/kernelLauncher.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
'use strict';
44

55
import { ChildProcess } from 'child_process';
6-
import { inject, injectable } from 'inversify';
6+
import { inject, injectable, named } from 'inversify';
77
import * as portfinder from 'portfinder';
88
import { promisify } from 'util';
99
import * as uuid from 'uuid/v4';
@@ -12,10 +12,12 @@ import { InterpreterUri } from '../../common/installer/types';
1212
import { traceInfo, traceWarning } from '../../common/logger';
1313
import { IFileSystem, TemporaryFile } from '../../common/platform/types';
1414
import { IPythonExecutionFactory } from '../../common/process/types';
15+
import { IOutputChannel } from '../../common/types';
1516
import { createDeferred, Deferred } from '../../common/utils/async';
1617
import * as localize from '../../common/utils/localize';
1718
import { noop } from '../../common/utils/misc';
1819
import { IInterpreterService } from '../../interpreter/contracts';
20+
import { JUPYTER_OUTPUT_CHANNEL } from '../constants';
1921
import { IJupyterKernelSpec } from '../types';
2022
import { findIndexOfConnectionFile } from './kernelFinder';
2123
import { IKernelConnection, IKernelFinder, IKernelLauncher, IKernelProcess } from './types';
@@ -49,6 +51,7 @@ class KernelProcess implements IKernelProcess {
4951
private executionFactory: IPythonExecutionFactory,
5052
private interpreterService: IInterpreterService,
5153
private file: IFileSystem,
54+
private outputChannel: IOutputChannel,
5255
private _connection: IKernelConnection,
5356
private _kernelSpec: IJupyterKernelSpec
5457
) {
@@ -82,11 +85,15 @@ class KernelProcess implements IKernelProcess {
8285
interpreter: matchingInterpreter
8386
});
8487

88+
this.outputChannel.appendLine(localize.DataScience.connectingIPyKernel());
89+
8590
// Then launch that process, also merging in the environment in the kernelspec
8691
const exeObs = executionService.execObservable(args, { extraVariables: this._kernelSpec.env });
8792

8893
if (exeObs.proc) {
8994
exeObs.proc!.on('exit', (exitCode) => {
95+
// tslint:disable-next-line: messages-must-be-localized
96+
this.outputChannel.appendLine(`Kernel died with exit code: ${exitCode}`);
9097
traceInfo('KernelProcess Exit', `Exit - ${exitCode}`);
9198
if (!this.readyPromise.completed) {
9299
this.readyPromise.reject(new Error(localize.DataScience.rawKernelProcessExitBeforeConnect()));
@@ -100,13 +107,18 @@ class KernelProcess implements IKernelProcess {
100107
exeObs.out.subscribe((output) => {
101108
if (output.source === 'stderr') {
102109
traceWarning(`StdErr from Kernel Process ${output.out}`);
110+
this.outputChannel.appendLine(output.out);
103111
} else {
104112
// Search for --existing this is the message that will indicate that our kernel is actually
105113
// up and started from stdout
106114
// To connect another client to this kernel, use:
107115
// --existing /var/folders/q7/cn8fg6s94fgdcl0h7rbxldf00000gn/T/tmp-16231TOL2dgBoWET1.json
116+
// Is this going to work with non-python?
108117
if (!this.readyPromise.completed && output.out.includes('--existing')) {
109118
this.readyPromise.resolve();
119+
this.outputChannel.appendLine(localize.DataScience.connectedToIPyKernel());
120+
} else if (this.readyPromise.resolved) {
121+
this.outputChannel.appendLine(output.out);
110122
}
111123
traceInfo(output.out);
112124
}
@@ -133,7 +145,8 @@ export class KernelLauncher implements IKernelLauncher {
133145
@inject(IKernelFinder) private kernelFinder: IKernelFinder,
134146
@inject(IPythonExecutionFactory) private executionFactory: IPythonExecutionFactory,
135147
@inject(IInterpreterService) private interpreterService: IInterpreterService,
136-
@inject(IFileSystem) private file: IFileSystem
148+
@inject(IFileSystem) private file: IFileSystem,
149+
@inject(IOutputChannel) @named(JUPYTER_OUTPUT_CHANNEL) private jupyterOutput: IOutputChannel
137150
) {}
138151

139152
public async launch(
@@ -154,6 +167,7 @@ export class KernelLauncher implements IKernelLauncher {
154167
this.executionFactory,
155168
this.interpreterService,
156169
this.file,
170+
this.jupyterOutput,
157171
connection,
158172
kernelSpec
159173
);

src/client/datascience/raw-kernel/enchannel-zmq-backend-6/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,9 @@ class SocketEventEmitter extends Events.EventEmitter {
150150
this.emit('message', b);
151151
setTimeout(this.waitForReceive.bind(this, socket), 0);
152152
})
153-
.ignoreErrors();
153+
.catch((exc) => {
154+
traceError('Exception communicating with kernel:', exc);
155+
});
154156
}
155157
}
156158
}

src/client/datascience/raw-kernel/enchannelJMPConnection.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { KernelMessage } from '@jupyterlab/services';
22
import type { Channels } from '@nteract/messaging';
33
import { injectable } from 'inversify';
4+
import { noop } from '../../common/utils/misc';
45
import { IJMPConnection, IJMPConnectionInfo } from '../types';
56

67
@injectable()
@@ -24,10 +25,11 @@ export class EnchannelJMPConnection implements IJMPConnection {
2425
this.mainChannel.next(message as any);
2526
}
2627
}
27-
public subscribe(handlerFunc: (message: KernelMessage.IMessage) => void) {
28+
// tslint:disable-next-line: no-any
29+
public subscribe(handlerFunc: (message: KernelMessage.IMessage) => void, errorHandler?: (exc: any) => void) {
2830
if (this.mainChannel) {
2931
// tslint:disable-next-line:no-any
30-
this.mainChannel.subscribe(handlerFunc as any);
32+
this.mainChannel.subscribe(handlerFunc as any, errorHandler ? errorHandler : noop);
3133
}
3234
}
3335

src/client/datascience/raw-kernel/rawJupyterSession.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,11 @@ export class RawJupyterSession extends BaseJupyterSession {
5757
): Promise<IJupyterKernelSpec | undefined> {
5858
// Save the resource that we connect with
5959
this.resource = resource;
60+
let newSession: RawSession | null | CancellationError = null;
6061
try {
6162
// Try to start up our raw session, allow for cancellation or timeout
6263
// Notebook Provider level will handle the thrown error
63-
const newSession = await waitForPromise(
64+
newSession = await waitForPromise(
6465
Promise.race([
6566
this.startRawSession(resource, kernelName),
6667
createPromiseFromCancellation({
@@ -81,7 +82,7 @@ export class RawJupyterSession extends BaseJupyterSession {
8182
throw new Error(localize.DataScience.sessionDisposed());
8283
} else {
8384
traceInfo('Raw session started and connected');
84-
this.session = newSession;
85+
this.setSession(newSession);
8586
this.kernelSpec = newSession.kernelProcess?.kernelSpec;
8687
}
8788
} catch (error) {
@@ -94,7 +95,7 @@ export class RawJupyterSession extends BaseJupyterSession {
9495
this.startRestartSession();
9596

9697
this.connected = true;
97-
return (this.session as RawSession).kernelProcess.kernelSpec;
98+
return (newSession as RawSession).kernelProcess.kernelSpec;
9899
}
99100

100101
public async createNewKernelSession(
@@ -109,8 +110,8 @@ export class RawJupyterSession extends BaseJupyterSession {
109110
return this.startRawSession(this.resource, kernel);
110111
}
111112

112-
protected set session(session: ISessionWithSocket | undefined) {
113-
super.session = session;
113+
protected setSession(session: ISessionWithSocket | undefined) {
114+
super.setSession(session);
114115

115116
// When setting the session clear our current exit handler and hook up to the
116117
// new session process

src/client/datascience/raw-kernel/rawKernel.ts

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Licensed under the MIT License.
33
import type { Kernel, KernelMessage, ServerConnection } from '@jupyterlab/services';
44
import * as uuid from 'uuid/v4';
5-
import { KernelSocketWrapper } from '../kernelSocketWrapper';
5+
import { IWebSocketLike, KernelSocketWrapper } from '../kernelSocketWrapper';
66
import { IJMPConnection, IKernelSocket } from '../types';
77
import { RawSocket } from './rawSocket';
88

@@ -65,41 +65,13 @@ export class RawKernel implements Kernel.IKernel {
6565
public get isDisposed(): boolean {
6666
return this.realKernel.isDisposed;
6767
}
68-
private realKernel: Kernel.IKernel;
69-
constructor(connection: IJMPConnection, name: string, clientId: string) {
70-
// Dummy websocket we give to the underlying real kernel
71-
let socketInstance: any;
72-
class RawSocketWrapper extends KernelSocketWrapper(RawSocket) {
73-
constructor() {
74-
super(connection, clientId);
75-
socketInstance = this;
76-
}
77-
}
78-
79-
// Remap the server settings for the real kernel to use our dummy websocket
80-
// tslint:disable-next-line: no-require-imports
81-
const jupyterLab = require('@jupyterlab/services') as typeof import('@jupyterlab/services');
82-
const settings = jupyterLab.ServerConnection.makeSettings({
83-
WebSocket: RawSocketWrapper as any,
84-
wsUrl: 'BOGUS_PVSC'
85-
});
86-
87-
// Then create the real kernel
88-
// tslint:disable-next-line: no-require-imports
89-
const defaultImport = require('@jupyterlab/services/lib/kernel/default') as typeof import('@jupyterlab/services/lib/kernel/default');
90-
this.realKernel = new defaultImport.DefaultKernel(
91-
{
92-
name,
93-
serverSettings: settings,
94-
clientId,
95-
handleComms: true
96-
},
97-
uuid()
98-
);
99-
68+
constructor(private realKernel: Kernel.IKernel, socket: IKernelSocket & IWebSocketLike) {
10069
// Save this raw socket as our kernel socket. It will be
10170
// used to watch and respond to kernel messages.
102-
this.socket = socketInstance;
71+
this.socket = socket;
72+
73+
// Pretend like an open occurred. This will prime the real kernel to be connected
74+
socket.emit('open');
10375
}
10476

10577
public shutdown(): Promise<void> {
@@ -222,3 +194,38 @@ export class RawKernel implements Kernel.IKernel {
222194
this.realKernel.removeMessageHook(msgId, hook);
223195
}
224196
}
197+
198+
export function createRawKernel(connection: IJMPConnection, name: string, clientId: string): RawKernel {
199+
// Dummy websocket we give to the underlying real kernel
200+
let socketInstance: any;
201+
class RawSocketWrapper extends KernelSocketWrapper(RawSocket) {
202+
constructor() {
203+
super(connection, clientId);
204+
socketInstance = this;
205+
}
206+
}
207+
208+
// Remap the server settings for the real kernel to use our dummy websocket
209+
// tslint:disable-next-line: no-require-imports
210+
const jupyterLab = require('@jupyterlab/services') as typeof import('@jupyterlab/services');
211+
const settings = jupyterLab.ServerConnection.makeSettings({
212+
WebSocket: RawSocketWrapper as any,
213+
wsUrl: 'BOGUS_PVSC'
214+
});
215+
216+
// Then create the real kernel
217+
// tslint:disable-next-line: no-require-imports
218+
const defaultImport = require('@jupyterlab/services/lib/kernel/default') as typeof import('@jupyterlab/services/lib/kernel/default');
219+
const realKernel = new defaultImport.DefaultKernel(
220+
{
221+
name,
222+
serverSettings: settings,
223+
clientId,
224+
handleComms: true
225+
},
226+
uuid()
227+
);
228+
229+
// Use this real kernel in result.
230+
return new RawKernel(realKernel, socketInstance);
231+
}

0 commit comments

Comments
 (0)