5
5
import { ChildProcess } from 'child_process' ;
6
6
import { Event , EventEmitter } from 'vscode' ;
7
7
import { PYTHON_LANGUAGE } from '../../common/constants' ;
8
- import { WrappedError } from '../../common/errors/errorUtils' ;
9
8
import { traceError , traceInfo , traceWarning } from '../../common/logger' ;
10
9
import { IFileSystem , TemporaryFile } from '../../common/platform/types' ;
11
10
import { IProcessServiceFactory , IPythonExecutionFactory , ObservableExecutionResult } from '../../common/process/types' ;
12
11
import { Resource } from '../../common/types' ;
13
- import { createDeferred , Deferred , sleep } from '../../common/utils/async' ;
14
- import * as localize from '../../common/utils/localize' ;
15
12
import { noop , swallowExceptions } from '../../common/utils/misc' ;
16
13
import { IJupyterKernelSpec } from '../types' ;
17
14
import { findIndexOfConnectionFile } from './kernelFinder' ;
@@ -24,10 +21,7 @@ import cloneDeep = require('lodash/cloneDeep');
24
21
// Launches and disposes a kernel process given a kernelspec and a resource or python interpreter.
25
22
// Exposes connection information and the process itself.
26
23
export class KernelProcess implements IKernelProcess {
27
- public get ready ( ) : Promise < void > {
28
- return this . readyPromise . promise ;
29
- }
30
- public get exited ( ) : Event < number | null > {
24
+ public get exited ( ) : Event < { exitCode ?: number ; reason ?: string } > {
31
25
return this . exitEvent . event ;
32
26
}
33
27
public get kernelSpec ( ) : Readonly < IJupyterKernelSpec > {
@@ -41,10 +35,10 @@ export class KernelProcess implements IKernelProcess {
41
35
}
42
36
private _process ?: ChildProcess ;
43
37
private connectionFile ?: TemporaryFile ;
44
- private readyPromise : Deferred < void > ;
45
- private exitEvent : EventEmitter < number | null > = new EventEmitter < number | null > ( ) ;
38
+ private exitEvent = new EventEmitter < { exitCode ?: number ; reason ?: string } > ( ) ;
46
39
private pythonKernelLauncher ?: PythonKernelLauncherDaemon ;
47
40
private launchedOnce ?: boolean ;
41
+ private disposed ?: boolean ;
48
42
private kernelDaemon ?: IPythonKernelDaemon ;
49
43
private readonly _kernelSpec : IJupyterKernelSpec ;
50
44
private readonly originalKernelSpec : IJupyterKernelSpec ;
@@ -58,7 +52,6 @@ export class KernelProcess implements IKernelProcess {
58
52
) {
59
53
this . originalKernelSpec = kernelSpec ;
60
54
this . _kernelSpec = cloneDeep ( kernelSpec ) ;
61
- this . readyPromise = createDeferred < void > ( ) ;
62
55
}
63
56
public async interrupt ( ) : Promise < void > {
64
57
if ( this . kernelDaemon ) {
@@ -75,12 +68,6 @@ export class KernelProcess implements IKernelProcess {
75
68
76
69
const exeObs = await this . launchAsObservable ( ) ;
77
70
78
- sleep ( 1_000 )
79
- . then ( ( ) => {
80
- this . readyPromise . resolve ( ) ;
81
- } )
82
- . catch ( noop ) ;
83
-
84
71
let stdout = '' ;
85
72
let stderr = '' ;
86
73
exeObs . out . subscribe (
@@ -91,38 +78,29 @@ export class KernelProcess implements IKernelProcess {
91
78
traceWarning ( `StdErr from Kernel Process ${ output . out } ` ) ;
92
79
} else {
93
80
stdout += output . out ;
94
- // Search for --existing this is the message that will indicate that our kernel is actually
95
- // up and started from stdout
96
- // To connect another client to this kernel, use:
97
- // --existing /var/folders/q7/cn8fg6s94fgdcl0h7rbxldf00000gn/T/tmp-16231TOL2dgBoWET1.json
98
- if ( ! this . readyPromise . completed && stdout . includes ( '--existing' ) ) {
99
- this . readyPromise . resolve ( ) ;
100
- }
101
- traceInfo ( output . out ) ;
81
+ traceInfo ( `Kernel Output: ${ stdout } ` ) ;
102
82
}
103
83
} ,
104
84
( error ) => {
105
- if ( this . readyPromise . completed ) {
106
- traceInfo ( 'KernelProcess Error' , error , stderr ) ;
107
- } else {
108
- traceError ( 'Kernel died before it could start' , error , stderr ) ;
109
- // Include original error and stderr in error thrown.
110
- const errorMessage = `${ localize . DataScience . rawKernelProcessExitBeforeConnect ( ) } . Error = ${ error } , stderr = ${ stderr } ` ;
111
- const errorToWrap = error instanceof Error ? error : new Error ( error ) ;
112
- this . readyPromise . reject ( new WrappedError ( errorMessage , errorToWrap ) ) ;
85
+ if ( this . disposed ) {
86
+ traceInfo ( 'Kernel died' , error , stderr ) ;
87
+ return ;
113
88
}
89
+ traceError ( 'Kernel died' , error , stderr ) ;
114
90
if ( error instanceof PythonKernelDiedError ) {
115
- traceInfo ( 'KernelProcess Exit' , `Exit - ${ error . exitCode } ` ) ;
116
- this . exitEvent . fire ( error . exitCode ) ;
117
-
118
- // As the kernel has died, kill the daemon.
119
- this . kernelDaemon ?. kill ( ) . catch ( noop ) ; // NOSONAR
91
+ if ( this . disposed ) {
92
+ traceInfo ( 'KernelProcess Exit' , `Exit - ${ error . exitCode } , ${ error . reason } ` , error ) ;
93
+ } else {
94
+ traceError ( 'KernelProcess Exit' , `Exit - ${ error . exitCode } , ${ error . reason } ` , error ) ;
95
+ }
96
+ this . exitEvent . fire ( { exitCode : error . exitCode , reason : error . reason || error . message } ) ;
120
97
}
121
98
}
122
99
) ;
123
100
}
124
101
125
102
public async dispose ( ) : Promise < void > {
103
+ this . disposed = true ;
126
104
if ( this . kernelDaemon ) {
127
105
await this . kernelDaemon . kill ( ) . catch ( noop ) ;
128
106
swallowExceptions ( ( ) => this . kernelDaemon ?. dispose ( ) ) ;
@@ -167,16 +145,12 @@ export class KernelProcess implements IKernelProcess {
167
145
}
168
146
169
147
if ( exeObs . proc ) {
170
- exeObs . proc ! . on ( 'exit' , ( exitCode ) => {
148
+ exeObs . proc . on ( 'exit' , ( exitCode ) => {
171
149
traceInfo ( 'KernelProcess Exit' , `Exit - ${ exitCode } ` ) ;
172
- if ( ! this . readyPromise . completed ) {
173
- this . readyPromise . reject ( new Error ( localize . DataScience . rawKernelProcessExitBeforeConnect ( ) ) ) ;
174
- }
175
- this . exitEvent . fire ( exitCode ) ;
150
+ this . exitEvent . fire ( { exitCode : exitCode || undefined } ) ;
176
151
} ) ;
177
152
} else {
178
- traceInfo ( 'KernelProcess failed to launch' ) ;
179
- this . readyPromise . reject ( new Error ( localize . DataScience . rawKernelProcessNotStarted ( ) ) ) ;
153
+ throw new Error ( 'KernelProcess failed to launch' ) ;
180
154
}
181
155
182
156
this . _process = exeObs . proc ;
0 commit comments