Skip to content

Commit ed99ddc

Browse files
authored
[Gateway] Remove redundant list kernels request during session poll (#1112)
* Remove redundant list kernels request during session poll * Cull kernel in gateway kernel and session lifecycle tests
1 parent 770cd3e commit ed99ddc

File tree

2 files changed

+65
-18
lines changed

2 files changed

+65
-18
lines changed

jupyter_server/gateway/managers.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -297,18 +297,21 @@ async def get_kernel_spec_resource(self, kernel_name, path):
297297
class GatewaySessionManager(SessionManager):
298298
kernel_manager = Instance("jupyter_server.gateway.managers.GatewayMappingKernelManager")
299299

300-
async def kernel_culled(self, kernel_id):
300+
async def kernel_culled(self, kernel_id: str) -> bool:
301301
"""Checks if the kernel is still considered alive and returns true if it's not found."""
302-
kernel = None
302+
km: Optional[GatewayKernelManager] = None
303303
try:
304+
# Since we keep the models up-to-date via client polling, use that state to determine
305+
# if this kernel no longer exists on the gateway server rather than perform a redundant
306+
# fetch operation - especially since this is called at approximately the same interval.
307+
# This has the effect of reducing GET /api/kernels requests against the gateway server
308+
# by 50%!
309+
# Note that should the redundant polling be consolidated, or replaced with an event-based
310+
# notification model, this will need to be revisited.
304311
km = self.kernel_manager.get_kernel(kernel_id)
305-
kernel = await km.refresh_model()
306312
except Exception: # Let exceptions here reflect culled kernel
307313
pass
308-
return kernel is None
309-
310-
311-
"""KernelManager class to manage a kernel running on a Gateway Server via the REST API"""
314+
return km is None
312315

313316

314317
class GatewayKernelManager(AsyncKernelManager):

tests/test_gateway.py

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -422,33 +422,49 @@ async def test_gateway_get_named_kernelspec(init_gateway, jp_fetch):
422422
assert expected_http_error(e, 404)
423423

424424

425-
async def test_gateway_session_lifecycle(init_gateway, jp_root_dir, jp_fetch):
425+
@pytest.mark.parametrize("cull_kernel", [False, True])
426+
async def test_gateway_session_lifecycle(init_gateway, jp_root_dir, jp_fetch, cull_kernel):
426427
# Validate session lifecycle functions; create and delete.
427428

428429
# create
429430
session_id, kernel_id = await create_session(jp_root_dir, jp_fetch, "kspec_foo")
430431

431432
# ensure kernel still considered running
432-
assert await is_kernel_running(jp_fetch, kernel_id) is True
433+
assert await is_session_active(jp_fetch, session_id) is True
433434

434435
# interrupt
435436
await interrupt_kernel(jp_fetch, kernel_id)
436437

437438
# ensure kernel still considered running
438-
assert await is_kernel_running(jp_fetch, kernel_id) is True
439+
assert await is_session_active(jp_fetch, session_id) is True
439440

440441
# restart
441442
await restart_kernel(jp_fetch, kernel_id)
442443

443-
# ensure kernel still considered running
444-
assert await is_kernel_running(jp_fetch, kernel_id) is True
444+
assert await is_session_active(jp_fetch, session_id) is True
445445

446-
# delete
447-
await delete_session(jp_fetch, session_id)
448-
assert await is_kernel_running(jp_fetch, kernel_id) is False
446+
if cull_kernel:
447+
running_kernels.pop(kernel_id)
448+
449+
# fetch kernel and session and ensure not considered running
450+
assert await is_kernel_running(jp_fetch, kernel_id) is not cull_kernel
451+
assert await is_session_active(jp_fetch, session_id) is not cull_kernel
452+
453+
# delete session. If culled, ensure 404 is raised
454+
if cull_kernel:
455+
with pytest.raises(tornado.httpclient.HTTPClientError) as e:
456+
await delete_session(jp_fetch, session_id)
457+
assert expected_http_error(e, 404)
458+
else:
459+
await delete_session(jp_fetch, session_id)
460+
461+
assert await is_session_active(jp_fetch, session_id) is False
449462

450463

451-
async def test_gateway_kernel_lifecycle(init_gateway, jp_serverapp, jp_ws_fetch, jp_fetch):
464+
@pytest.mark.parametrize("cull_kernel", [False, True])
465+
async def test_gateway_kernel_lifecycle(
466+
init_gateway, jp_serverapp, jp_ws_fetch, jp_fetch, cull_kernel
467+
):
452468
# Validate kernel lifecycle functions; create, interrupt, restart and delete.
453469

454470
# create
@@ -475,8 +491,20 @@ async def test_gateway_kernel_lifecycle(init_gateway, jp_serverapp, jp_ws_fetch,
475491
# ensure kernel still considered running
476492
assert await is_kernel_running(jp_fetch, kernel_id) is True
477493

478-
# delete
479-
await delete_kernel(jp_fetch, kernel_id)
494+
if cull_kernel:
495+
running_kernels.pop(kernel_id)
496+
497+
# fetch kernel and session and ensure not considered running
498+
assert await is_kernel_running(jp_fetch, kernel_id) is not cull_kernel
499+
500+
# delete kernel. If culled, ensure 404 is raised
501+
if cull_kernel:
502+
with pytest.raises(tornado.httpclient.HTTPClientError) as e:
503+
await delete_kernel(jp_fetch, kernel_id)
504+
assert expected_http_error(e, 404)
505+
else:
506+
await delete_kernel(jp_fetch, kernel_id)
507+
480508
assert await is_kernel_running(jp_fetch, kernel_id) is False
481509

482510

@@ -578,6 +606,22 @@ async def test_channel_queue_get_msg_when_response_router_had_finished():
578606
#
579607
# Test methods below...
580608
#
609+
610+
611+
async def is_session_active(jp_fetch, session_id):
612+
"""Issues request to get the set of running kernels"""
613+
with mocked_gateway:
614+
# Get list of running kernels
615+
r = await jp_fetch("api", "sessions", method="GET")
616+
assert r.code == 200
617+
sessions = json.loads(r.body.decode("utf-8"))
618+
assert len(sessions) == len(running_kernels) # Use running_kernels as truth
619+
for model in sessions:
620+
if model.get("id") == session_id:
621+
return True
622+
return False
623+
624+
581625
async def create_session(root_dir, jp_fetch, kernel_name):
582626
"""Creates a session for a kernel. The session is created against the server
583627
which then uses the gateway for kernel management.

0 commit comments

Comments
 (0)