Skip to content

Commit

Permalink
Ability to configure cull_idle_timeout with kernelSpec (#1342)
Browse files Browse the repository at this point in the history
Co-authored-by: Akshay Chitneni <achitneni@apple.com>
  • Loading branch information
akshaychitneni and Akshay Chitneni authored Oct 24, 2023
1 parent 393c108 commit b475f0e
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
5 changes: 4 additions & 1 deletion jupyter_server/services/kernels/kernelmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,9 @@ async def cull_kernel_if_idle(self, kernel_id):
await ensure_async(self.shutdown_kernel(kernel_id))
return

kernel_spec_metadata = kernel.kernel_spec.metadata
cull_idle_timeout = kernel_spec_metadata.get("cull_idle_timeout", self.cull_idle_timeout)

if hasattr(
kernel, "last_activity"
): # last_activity is monkey-patched, so ensure that has occurred
Expand All @@ -657,7 +660,7 @@ async def cull_kernel_if_idle(self, kernel_id):
dt_now = utcnow()
dt_idle = dt_now - kernel.last_activity
# Compute idle properties
is_idle_time = dt_idle > timedelta(seconds=self.cull_idle_timeout)
is_idle_time = dt_idle > timedelta(seconds=cull_idle_timeout)
is_idle_execute = self.cull_busy or (kernel.execution_state != "busy")
connections = self._kernel_connections.get(kernel_id, 0)
is_idle_connected = self.cull_connected or not connections
Expand Down
39 changes: 39 additions & 0 deletions tests/services/kernels/test_cull.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
CULL_TIMEOUT = 30 if platform.python_implementation() == "PyPy" else 5
CULL_INTERVAL = 1

sample_kernel_json_with_metadata = {
"argv": ["cat", "{connection_file}"],
"display_name": "Test kernel",
"metadata": {"cull_idle_timeout": 0},
}


@pytest.fixture(autouse=True)
def suppress_deprecation_warnings():
Expand All @@ -24,6 +30,21 @@ def suppress_deprecation_warnings():
yield


@pytest.fixture
def jp_kernelspec_with_metadata(jp_data_dir):
"""Configures some sample kernelspecs in the Jupyter data directory."""
kenrel_spec_name = "sample_with_metadata"
sample_kernel_dir = jp_data_dir.joinpath("kernels", kenrel_spec_name)
sample_kernel_dir.mkdir(parents=True)
# Create kernel json file
sample_kernel_file = sample_kernel_dir.joinpath("kernel.json")
kernel_json = sample_kernel_json_with_metadata.copy()
sample_kernel_file.write_text(json.dumps(kernel_json))
# Create resources text
sample_kernel_resources = sample_kernel_dir.joinpath("resource.txt")
sample_kernel_resources.write_text("resource")


@pytest.mark.parametrize(
"jp_server_config",
[
Expand Down Expand Up @@ -73,6 +94,24 @@ async def test_cull_idle(jp_fetch, jp_ws_fetch):
assert culled


async def test_cull_idle_disable(jp_fetch, jp_ws_fetch, jp_kernelspec_with_metadata):
r = await jp_fetch("api", "kernels", method="POST", allow_nonstandard_methods=True)
kernel = json.loads(r.body.decode())
kid = kernel["id"]

# Open a websocket connection.
ws = await jp_ws_fetch("api", "kernels", kid, "channels")

r = await jp_fetch("api", "kernels", kid, method="GET")
model = json.loads(r.body.decode())
assert model["connections"] == 1
culled = await get_cull_status(kid, jp_fetch) # connected, should not be culled
assert not culled
ws.close()
culled = await get_cull_status(kid, jp_fetch) # not connected, should not be culled
assert not culled


# Pending kernels was released in Jupyter Client 7.1
# It is currently broken on Windows (Jan 2022). When fixed, we can remove the Windows check.
# See https://github.com/jupyter-server/jupyter_server/issues/672
Expand Down

0 comments on commit b475f0e

Please sign in to comment.