-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Connect to raw kernel with command line args instead of connection file #11894
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Use command line arguments to launch our raw kernels as opposed to a connection file. The connection file seems to be causing issues in particular on windows CI machines with permissions. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,6 @@ import * as tcpPortUsed from 'tcp-port-used'; | |
import { Event, EventEmitter } from 'vscode'; | ||
import { PYTHON_LANGUAGE } from '../../common/constants'; | ||
import { traceError, traceInfo, traceWarning } from '../../common/logger'; | ||
import { IFileSystem, TemporaryFile } from '../../common/platform/types'; | ||
import { IProcessServiceFactory, ObservableExecutionResult } from '../../common/process/types'; | ||
import { Resource } from '../../common/types'; | ||
import { noop, swallowExceptions } from '../../common/utils/misc'; | ||
|
@@ -39,7 +38,6 @@ export class KernelProcess implements IKernelProcess { | |
return this.kernelSpec.language.toLowerCase() === PYTHON_LANGUAGE.toLowerCase(); | ||
} | ||
private _process?: ChildProcess; | ||
private connectionFile?: TemporaryFile; | ||
private exitEvent = new EventEmitter<{ exitCode?: number; reason?: string }>(); | ||
private pythonKernelLauncher?: PythonKernelLauncherDaemon; | ||
private launchedOnce?: boolean; | ||
|
@@ -49,7 +47,6 @@ export class KernelProcess implements IKernelProcess { | |
private readonly originalKernelSpec: IJupyterKernelSpec; | ||
constructor( | ||
private readonly processExecutionFactory: IProcessServiceFactory, | ||
private readonly file: IFileSystem, | ||
private readonly daemonPool: KernelDaemonPool, | ||
private readonly _connection: IKernelConnection, | ||
kernelSpec: IJupyterKernelSpec, | ||
|
@@ -72,7 +69,8 @@ export class KernelProcess implements IKernelProcess { | |
} | ||
this.launchedOnce = true; | ||
|
||
await this.createAndUpdateConnectionFile(); | ||
// Update our connection arguments in the kernel spec | ||
this.updateConnectionArgs(); | ||
|
||
const exeObs = await this.launchAsObservable(); | ||
|
||
|
@@ -127,7 +125,6 @@ export class KernelProcess implements IKernelProcess { | |
this.exitEvent.fire(); | ||
}); | ||
swallowExceptions(() => this.pythonKernelLauncher?.dispose()); | ||
swallowExceptions(() => this.connectionFile?.dispose()); | ||
} | ||
|
||
// Make sure that the heartbeat channel is open for connections | ||
|
@@ -144,21 +141,42 @@ export class KernelProcess implements IKernelProcess { | |
} | ||
} | ||
|
||
private async createAndUpdateConnectionFile() { | ||
// Create the connection file so that any user can destroy it. The kernel will | ||
// actually read it, delete it, and recreate it with more restricted permissions | ||
this.connectionFile = await this.file.createTemporaryFile('.json', 0o777); | ||
await this.file.writeFile(this.connectionFile.filePath, JSON.stringify(this._connection), { | ||
encoding: 'utf-8', | ||
flag: 'w' | ||
}); | ||
|
||
// Update the args in the kernelspec to include the conenction file. | ||
// Instead of having to use a connection file update our local copy of the kernelspec to launch | ||
// directly with command line arguments | ||
private updateConnectionArgs() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought briefly about where to handle this and I believe this is the right spot.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tested on windows as well. Not fully sure if this fixes the nightly test runs (as those issues don't seem to repro doing real python tests locally) so I'll queue up a run for that. I would expect this to fix the nightly test issues but even if there was another issue there this new method seems like a solid improvement, no messing around with creating and removing files. |
||
// First check to see if we have a kernelspec that expects a connection file, | ||
// Error if we don't have one. We expect '-f', '{connectionfile}' in our launch args | ||
const indexOfConnectionFile = findIndexOfConnectionFile(this._kernelSpec); | ||
if (indexOfConnectionFile === -1) { | ||
if ( | ||
indexOfConnectionFile === -1 || | ||
indexOfConnectionFile === 0 || | ||
this._kernelSpec.argv[indexOfConnectionFile - 1] !== '-f' | ||
) { | ||
throw new Error(`Connection file not found in kernelspec json args, ${this._kernelSpec.argv.join(' ')}`); | ||
} | ||
this._kernelSpec.argv[indexOfConnectionFile] = this.connectionFile.filePath; | ||
|
||
// Slice out -f and the connection file from the args | ||
this._kernelSpec.argv.splice(indexOfConnectionFile - 1, 2); | ||
|
||
// Add in our connection command line args | ||
this._kernelSpec.argv.push(...this.addConnectionArgs()); | ||
} | ||
|
||
// Add the command line arguments | ||
private addConnectionArgs(): string[] { | ||
const newConnectionArgs: string[] = []; | ||
|
||
newConnectionArgs.push(`--ip=${this._connection.ip}`); | ||
newConnectionArgs.push(`--stdin=${this._connection.stdin_port}`); | ||
newConnectionArgs.push(`--control=${this._connection.control_port}`); | ||
newConnectionArgs.push(`--hb=${this._connection.hb_port}`); | ||
newConnectionArgs.push(`--Session.signature_scheme="${this._connection.signature_scheme}"`); | ||
newConnectionArgs.push(`--Session.key=b"${this._connection.key}"`); // Note we need the 'b here at the start for a byte string | ||
newConnectionArgs.push(`--shell=${this._connection.shell_port}`); | ||
newConnectionArgs.push(`--transport="${this._connection.transport}"`); | ||
newConnectionArgs.push(`--iopub=${this._connection.iopub_port}`); | ||
|
||
return newConnectionArgs; | ||
} | ||
|
||
private async launchAsObservable() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That little x was bugging me 😆