5
5
"""
6
6
# Copyright (c) Jupyter Development Team.
7
7
# Distributed under the terms of the Modified BSD License.
8
+ import asyncio
8
9
import os
9
10
from collections import defaultdict
10
11
from datetime import datetime
@@ -209,16 +210,14 @@ async def start_kernel(self, kernel_id=None, path=None, **kwargs):
209
210
kwargs ["kernel_id" ] = kernel_id
210
211
kernel_id = await ensure_async (self .pinned_superclass .start_kernel (self , ** kwargs ))
211
212
self ._kernel_connections [kernel_id ] = 0
212
- self ._kernel_ports [kernel_id ] = self ._kernels [kernel_id ].ports
213
- self .start_watching_activity (kernel_id )
213
+ asyncio .ensure_future (self ._finish_kernel_start (kernel_id ))
214
+ # add busy/activity markers:
215
+ kernel = self .get_kernel (kernel_id )
216
+ kernel .execution_state = "starting"
217
+ kernel .reason = ""
218
+ kernel .last_activity = utcnow ()
214
219
self .log .info ("Kernel started: %s" % kernel_id )
215
220
self .log .debug ("Kernel args: %r" % kwargs )
216
- # register callback for failed auto-restart
217
- self .add_restart_callback (
218
- kernel_id ,
219
- lambda : self ._handle_kernel_died (kernel_id ),
220
- "dead" ,
221
- )
222
221
223
222
# Increase the metric of number of kernels running
224
223
# for the relevant kernel type by 1
@@ -233,6 +232,24 @@ async def start_kernel(self, kernel_id=None, path=None, **kwargs):
233
232
234
233
return kernel_id
235
234
235
+ async def _finish_kernel_start (self , kernel_id ):
236
+ km = self .get_kernel (kernel_id )
237
+ if hasattr (km , "ready" ):
238
+ try :
239
+ await km .ready
240
+ except Exception :
241
+ self .log .exception (km .ready .exception ())
242
+ return
243
+
244
+ self ._kernel_ports [kernel_id ] = km .ports
245
+ self .start_watching_activity (kernel_id )
246
+ # register callback for failed auto-restart
247
+ self .add_restart_callback (
248
+ kernel_id ,
249
+ lambda : self ._handle_kernel_died (kernel_id ),
250
+ "dead" ,
251
+ )
252
+
236
253
def ports_changed (self , kernel_id ):
237
254
"""Used by ZMQChannelsHandler to determine how to coordinate nudge and replays.
238
255
@@ -448,6 +465,8 @@ def kernel_model(self, kernel_id):
448
465
"execution_state" : kernel .execution_state ,
449
466
"connections" : self ._kernel_connections .get (kernel_id , 0 ),
450
467
}
468
+ if getattr (kernel , "reason" , None ):
469
+ model ["reason" ] = kernel .reason
451
470
return model
452
471
453
472
def list_kernels (self ):
@@ -479,6 +498,7 @@ def start_watching_activity(self, kernel_id):
479
498
kernel = self ._kernels [kernel_id ]
480
499
# add busy/activity markers:
481
500
kernel .execution_state = "starting"
501
+ kernel .reason = ""
482
502
kernel .last_activity = utcnow ()
483
503
kernel ._activity_stream = kernel .connect_iopub ()
484
504
session = Session (
@@ -507,7 +527,7 @@ def record_activity(msg_list):
507
527
def stop_watching_activity (self , kernel_id ):
508
528
"""Stop watching IOPub messages on a kernel for activity."""
509
529
kernel = self ._kernels [kernel_id ]
510
- if kernel . _activity_stream :
530
+ if getattr ( kernel , " _activity_stream" , None ) :
511
531
kernel ._activity_stream .close ()
512
532
kernel ._activity_stream = None
513
533
@@ -561,6 +581,17 @@ async def cull_kernels(self):
561
581
562
582
async def cull_kernel_if_idle (self , kernel_id ):
563
583
kernel = self ._kernels [kernel_id ]
584
+
585
+ if getattr (kernel , "execution_state" ) == "dead" :
586
+ self .log .warning (
587
+ "Culling '%s' dead kernel '%s' (%s)." ,
588
+ kernel .execution_state ,
589
+ kernel .kernel_name ,
590
+ kernel_id ,
591
+ )
592
+ await ensure_async (self .shutdown_kernel (kernel_id ))
593
+ return
594
+
564
595
if hasattr (
565
596
kernel , "last_activity"
566
597
): # last_activity is monkey-patched, so ensure that has occurred
0 commit comments