@@ -171,7 +171,10 @@ export class KernelConnector {
171
171
{
172
172
kernel : Deferred < {
173
173
kernel : IKernel ;
174
- deadKernelAction ?: 'deadKernelWasRestarted' | 'deadKernelWasNoRestarted' ;
174
+ deadKernelAction ?:
175
+ | 'deadKernelNeedsToBeRestarted'
176
+ | 'deadKernelWasNoRestarted'
177
+ | 'deadKernelWasRestarted' ;
175
178
} > ;
176
179
options : IDisplayOptions ;
177
180
}
@@ -181,7 +184,10 @@ export class KernelConnector {
181
184
{
182
185
kernel : Deferred < {
183
186
kernel : IBaseKernel ;
184
- deadKernelAction ?: 'deadKernelWasRestarted' | 'deadKernelWasNoRestarted' ;
187
+ deadKernelAction ?:
188
+ | 'deadKernelNeedsToBeRestarted'
189
+ | 'deadKernelWasNoRestarted'
190
+ | 'deadKernelWasRestarted' ;
185
191
} > ;
186
192
options : IDisplayOptions ;
187
193
}
@@ -194,17 +200,25 @@ export class KernelConnector {
194
200
promise :
195
201
| Promise < {
196
202
kernel : IBaseKernel ;
197
- deadKernelAction ?: 'deadKernelWasRestarted' | 'deadKernelWasNoRestarted' ;
203
+ deadKernelAction ?:
204
+ | 'deadKernelNeedsToBeRestarted'
205
+ | 'deadKernelWasNoRestarted'
206
+ | 'deadKernelWasRestarted' ;
198
207
} >
199
208
| Promise < {
200
209
kernel : IKernel ;
201
- deadKernelAction ?: 'deadKernelWasRestarted' | 'deadKernelWasNoRestarted' ;
210
+ deadKernelAction ?:
211
+ | 'deadKernelNeedsToBeRestarted'
212
+ | 'deadKernelWasNoRestarted'
213
+ | 'deadKernelWasRestarted' ;
202
214
} > ,
203
215
actionSource : KernelActionSource ,
204
216
onAction : ( action : KernelAction , kernel : IBaseKernel ) => void ,
205
- disposables : IDisposable [ ]
217
+ disposables : IDisposable [ ] ,
218
+ kernelWasRestartedDueToDeadKernel ?: { kernelWasRestartedDueToDeadKernel : Deferred < boolean > }
206
219
) : Promise < IKernel | IBaseKernel > {
207
- const { kernel, deadKernelAction } = await promise ;
220
+ const info = await promise ;
221
+ const { kernel, deadKernelAction } = info ;
208
222
// Before returning, but without disposing the kernel, double check it's still valid
209
223
// If a restart didn't happen, then we can't connect. Throw an error.
210
224
// Do this outside of the loop so that subsequent calls will still ask because the kernel isn't disposed
@@ -215,9 +229,17 @@ export class KernelConnector {
215
229
if ( deadKernelAction === 'deadKernelWasNoRestarted' ) {
216
230
throw new KernelDeadError ( kernel . kernelConnectionMetadata ) ;
217
231
} else if ( deadKernelAction === 'deadKernelWasRestarted' ) {
218
- return kernel ;
232
+ throw new KernelDeadError ( kernel . kernelConnectionMetadata ) ;
233
+ } else if ( kernelWasRestartedDueToDeadKernel ?. kernelWasRestartedDueToDeadKernel . value === true ) {
234
+ throw new KernelDeadError ( kernel . kernelConnectionMetadata ) ;
219
235
}
236
+ info . deadKernelAction = 'deadKernelWasRestarted' ;
220
237
// Kernel is dead and we didn't prompt the user to restart it, hence re-run the code that will prompt the user for a restart.
238
+ const deferred = createDeferred < boolean > ( ) ;
239
+ deferred . resolve ( true ) ;
240
+ kernelWasRestartedDueToDeadKernel = kernelWasRestartedDueToDeadKernel || {
241
+ kernelWasRestartedDueToDeadKernel : deferred
242
+ } ;
221
243
return KernelConnector . wrapKernelMethod (
222
244
kernel . kernelConnectionMetadata ,
223
245
'start' ,
@@ -226,7 +248,8 @@ export class KernelConnector {
226
248
notebookResource ,
227
249
options ,
228
250
disposables ,
229
- onAction
251
+ onAction ,
252
+ kernelWasRestartedDueToDeadKernel
230
253
) ;
231
254
}
232
255
return kernel ;
@@ -240,7 +263,8 @@ export class KernelConnector {
240
263
notebookResource : NotebookResource ,
241
264
options : IDisplayOptions ,
242
265
disposables : IDisposable [ ] ,
243
- onAction : ( action : KernelAction , kernel : IBaseKernel | IKernel ) => void = ( ) => noop ( )
266
+ onAction : ( action : KernelAction , kernel : IBaseKernel | IKernel ) => void = ( ) => noop ( ) ,
267
+ kernelWasRestartedDueToDeadKernel ?: { kernelWasRestartedDueToDeadKernel : Deferred < boolean > }
244
268
) : Promise < IBaseKernel | IKernel > {
245
269
let currentPromise = this . getKernelInfo ( notebookResource ) ;
246
270
if ( ! options . disableUI && currentPromise ?. options . disableUI ) {
@@ -276,15 +300,22 @@ export class KernelConnector {
276
300
) } `
277
301
) ;
278
302
303
+ kernelWasRestartedDueToDeadKernel = kernelWasRestartedDueToDeadKernel || {
304
+ kernelWasRestartedDueToDeadKernel : createDeferred < boolean > ( )
305
+ } ;
279
306
const promise = KernelConnector . wrapKernelMethodImpl (
280
307
metadata ,
281
308
initialContext ,
282
309
serviceContainer ,
283
310
notebookResource ,
284
311
options ,
285
312
actionSource ,
286
- onAction
313
+ onAction ,
314
+ kernelWasRestartedDueToDeadKernel
287
315
) ;
316
+ if ( kernelWasRestartedDueToDeadKernel ?. kernelWasRestartedDueToDeadKernel . resolved ) {
317
+ kernelWasRestartedDueToDeadKernel . kernelWasRestartedDueToDeadKernel . resolve ( true ) ;
318
+ }
288
319
const deferred = createDeferredFromPromise ( promise ) ;
289
320
deferred . promise . catch ( noop ) ;
290
321
// If the kernel gets disposed or we fail to create the kernel, then ensure we remove the cached result.
@@ -310,7 +341,8 @@ export class KernelConnector {
310
341
deferred . promise ,
311
342
actionSource ,
312
343
onAction ,
313
- disposables
344
+ disposables ,
345
+ kernelWasRestartedDueToDeadKernel
314
346
) ;
315
347
}
316
348
private static getKernelInfo ( notebookResource : NotebookResource ) {
@@ -322,15 +354,23 @@ export class KernelConnector {
322
354
notebookResource : NotebookResource ,
323
355
deferred : Deferred < {
324
356
kernel : IBaseKernel ;
325
- deadKernelAction ?: 'deadKernelWasRestarted' | 'deadKernelWasNoRestarted' | undefined ;
357
+ deadKernelAction ?:
358
+ | 'deadKernelNeedsToBeRestarted'
359
+ | 'deadKernelWasNoRestarted'
360
+ | 'deadKernelWasRestarted'
361
+ | undefined ;
326
362
} > ,
327
363
options : IDisplayOptions
328
364
) {
329
365
if ( 'notebook' in notebookResource ) {
330
366
KernelConnector . connectionsByNotebook . set ( notebookResource . notebook , {
331
367
kernel : deferred as Deferred < {
332
368
kernel : IKernel ;
333
- deadKernelAction ?: 'deadKernelWasRestarted' | 'deadKernelWasNoRestarted' | undefined ;
369
+ deadKernelAction ?:
370
+ | 'deadKernelNeedsToBeRestarted'
371
+ | 'deadKernelWasNoRestarted'
372
+ | 'deadKernelWasRestarted'
373
+ | undefined ;
334
374
} > ,
335
375
options
336
376
} ) ;
@@ -342,7 +382,11 @@ export class KernelConnector {
342
382
notebookResource : NotebookResource ,
343
383
matchingKernelPromise ?: Promise < {
344
384
kernel : IBaseKernel ;
345
- deadKernelAction ?: 'deadKernelWasRestarted' | 'deadKernelWasNoRestarted' | undefined ;
385
+ deadKernelAction ?:
386
+ | 'deadKernelNeedsToBeRestarted'
387
+ | 'deadKernelWasNoRestarted'
388
+ | 'deadKernelWasRestarted'
389
+ | undefined ;
346
390
} >
347
391
) {
348
392
if ( ! matchingKernelPromise ) {
@@ -385,10 +429,11 @@ export class KernelConnector {
385
429
notebookResource : NotebookResource ,
386
430
options : IDisplayOptions ,
387
431
actionSource : KernelActionSource ,
388
- onAction : ( action : KernelAction , kernel : IBaseKernel ) => void
432
+ onAction : ( action : KernelAction , kernel : IBaseKernel ) => void ,
433
+ kernelWasRestartedDueToDeadKernel ?: { kernelWasRestartedDueToDeadKernel : Deferred < boolean > }
389
434
) : Promise < {
390
435
kernel : IBaseKernel | IKernel ;
391
- deadKernelAction ?: 'deadKernelWasRestarted ' | 'deadKernelWasNoRestarted' ;
436
+ deadKernelAction ?: 'deadKernelNeedsToBeRestarted ' | 'deadKernelWasNoRestarted' ;
392
437
} > {
393
438
const kernelProvider = serviceContainer . get < IKernelProvider > ( IKernelProvider ) ;
394
439
const thirdPartyKernelProvider = serviceContainer . get < IThirdPartyKernelProvider > ( IThirdPartyKernelProvider ) ;
@@ -416,15 +461,20 @@ export class KernelConnector {
416
461
resourceUri : notebookResource . resource
417
462
} ) ;
418
463
464
+ let attemptedToRestart = false ;
419
465
try {
420
466
// If the kernel is dead, ask the user if they want to restart.
421
467
// We need to perform this check first, as its possible we'd call this method for dead kernels.
422
468
// & if the kernel is dead, prompt to restart.
423
469
if ( initialContext !== 'restart' && isKernelDead ( kernel ) && ! options . disableUI ) {
470
+ attemptedToRestart = true ;
424
471
const restarted = await KernelConnector . notifyAndRestartDeadKernel ( kernel ) ;
472
+ if ( restarted && kernelWasRestartedDueToDeadKernel ) {
473
+ kernelWasRestartedDueToDeadKernel . kernelWasRestartedDueToDeadKernel . resolve ( true ) ;
474
+ }
425
475
return {
426
476
kernel,
427
- deadKernelAction : restarted ? 'deadKernelWasRestarted ' : 'deadKernelWasNoRestarted'
477
+ deadKernelAction : restarted ? 'deadKernelNeedsToBeRestarted ' : 'deadKernelWasNoRestarted'
428
478
} ;
429
479
} else {
430
480
onAction ( currentContext , kernel ) ;
@@ -440,6 +490,10 @@ export class KernelConnector {
440
490
}
441
491
}
442
492
} catch ( error ) {
493
+ if ( attemptedToRestart && kernelWasRestartedDueToDeadKernel ) {
494
+ kernelWasRestartedDueToDeadKernel . kernelWasRestartedDueToDeadKernel . resolve ( true ) ;
495
+ }
496
+
443
497
if ( ! isCancellationError ( error ) ) {
444
498
logger . warn (
445
499
`Error occurred while trying to ${ currentContext } the kernel, options.disableUI=${ options . disableUI } ` ,
0 commit comments