Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/source/api/jupyter_server.services.kernels.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ Submodules
:undoc-members:


.. automodule:: jupyter_server.services.kernels.routing
:members:
:show-inheritance:
:undoc-members:


.. automodule:: jupyter_server.services.kernels.websocket
:members:
:show-inheritance:
Expand Down
34 changes: 18 additions & 16 deletions jupyter_server/gateway/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import datetime
import json
import os
import warnings
from queue import Empty, Queue
from threading import Thread
from time import monotonic
Expand All @@ -30,7 +31,9 @@
emit_kernel_action_event,
)
from ..services.sessions.sessionmanager import SessionManager
from ..transutils import _i18n
from ..utils import url_path_join
from .connections import GatewayWebSocketConnection
from .gateway_client import GatewayClient, gateway_request

if TYPE_CHECKING:
Expand Down Expand Up @@ -211,6 +214,13 @@ async def cull_kernels(self):
await self.list_kernels()
await super().cull_kernels()

@property
def info(self):
return (
_i18n("\nKernels will be managed by the Gateway server running at:\n%s")
% self.kernels_url
)


class GatewayKernelSpecManager(KernelSpecManager):
"""A gateway kernel spec manager."""
Expand Down Expand Up @@ -359,22 +369,13 @@ class GatewaySessionManager(SessionManager):

kernel_manager = Instance("jupyter_server.gateway.managers.GatewayMappingKernelManager")

async def kernel_culled(self, kernel_id: str) -> bool: # typing: ignore
"""Checks if the kernel is still considered alive and returns true if it's not found."""
km: Optional[GatewayKernelManager] = None
try:
# Since we keep the models up-to-date via client polling, use that state to determine
# if this kernel no longer exists on the gateway server rather than perform a redundant
# fetch operation - especially since this is called at approximately the same interval.
# This has the effect of reducing GET /api/kernels requests against the gateway server
# by 50%!
# Note that should the redundant polling be consolidated, or replaced with an event-based
# notification model, this will need to be revisited.
km = self.kernel_manager.get_kernel(kernel_id)
except Exception:
# Let exceptions here reflect culled kernel
pass
return km is None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
warnings.warn(
"The GatewaySessionManager class is deprecated and will not be supported in Jupyter Server 3.0",
DeprecationWarning,
stacklevel=2,
)


class GatewayKernelManager(ServerKernelManager):
Expand Down Expand Up @@ -406,6 +407,7 @@ def has_kernel(self):

client_class = DottedObjectName("jupyter_server.gateway.managers.GatewayKernelClient")
client_factory = Type(klass="jupyter_server.gateway.managers.GatewayKernelClient")
websocket_connection_class = GatewayWebSocketConnection

# --------------------------------------------------------------------------
# create a Client connected to our Kernel
Expand Down
43 changes: 19 additions & 24 deletions jupyter_server/serverapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,7 @@
from jupyter_server.extension.config import ExtensionConfigManager
from jupyter_server.extension.manager import ExtensionManager
from jupyter_server.extension.serverextension import ServerExtensionApp
from jupyter_server.gateway.connections import GatewayWebSocketConnection
from jupyter_server.gateway.gateway_client import GatewayClient
from jupyter_server.gateway.managers import (
GatewayKernelSpecManager,
GatewayMappingKernelManager,
GatewaySessionManager,
)
from jupyter_server.log import log_request
from jupyter_server.prometheus.metrics import (
ACTIVE_DURATION,
Expand All @@ -131,6 +125,10 @@
AsyncMappingKernelManager,
MappingKernelManager,
)
from jupyter_server.services.kernels.routing import (
RoutingKernelSpecManager,
RoutingMappingKernelManager,
)
from jupyter_server.services.sessions.sessionmanager import SessionManager
from jupyter_server.utils import (
JupyterServerAuthWarning,
Expand Down Expand Up @@ -893,14 +891,12 @@ class ServerApp(JupyterApp):
AsyncContentsManager,
AsyncFileContentsManager,
NotebookNotary,
GatewayMappingKernelManager,
GatewayKernelSpecManager,
GatewaySessionManager,
GatewayWebSocketConnection,
GatewayClient,
Authorizer,
EventLogger,
ZMQChannelsWebsocketConnection,
RoutingKernelSpecManager,
RoutingMappingKernelManager,
]

subcommands: dict[str, t.Any] = {
Expand Down Expand Up @@ -1621,9 +1617,7 @@ def template_file_path(self) -> list[str]:

@default("kernel_manager_class")
def _default_kernel_manager_class(self) -> t.Union[str, type[AsyncMappingKernelManager]]:
if self.gateway_config.gateway_enabled:
return "jupyter_server.gateway.managers.GatewayMappingKernelManager"
return AsyncMappingKernelManager
return RoutingMappingKernelManager

session_manager_class = Type(
config=True,
Expand All @@ -1632,8 +1626,6 @@ def _default_kernel_manager_class(self) -> t.Union[str, type[AsyncMappingKernelM

@default("session_manager_class")
def _default_session_manager_class(self) -> t.Union[str, type[SessionManager]]:
if self.gateway_config.gateway_enabled:
return "jupyter_server.gateway.managers.GatewaySessionManager"
return SessionManager

kernel_websocket_connection_class = Type(
Expand All @@ -1646,8 +1638,11 @@ def _default_session_manager_class(self) -> t.Union[str, type[SessionManager]]:
def _default_kernel_websocket_connection_class(
self,
) -> t.Union[str, type[ZMQChannelsWebsocketConnection]]:
if self.gateway_config.gateway_enabled:
return "jupyter_server.gateway.connections.GatewayWebSocketConnection"
if issubclass(
self.kernel_manager_class,
RoutingMappingKernelManager,
):
return "jupyter_server.services.kernels.routing.RoutingKernelManagerWebsocketConnection"
return ZMQChannelsWebsocketConnection

websocket_ping_interval = Integer(
Expand Down Expand Up @@ -1697,8 +1692,11 @@ def _default_kernel_websocket_connection_class(

@default("kernel_spec_manager_class")
def _default_kernel_spec_manager_class(self) -> t.Union[str, type[KernelSpecManager]]:
if self.gateway_config.gateway_enabled:
return "jupyter_server.gateway.managers.GatewayKernelSpecManager"
if issubclass(
self.kernel_manager_class,
RoutingMappingKernelManager,
):
return RoutingKernelSpecManager
return KernelSpecManager

login_handler_class = Type(
Expand Down Expand Up @@ -2877,11 +2875,8 @@ def running_server_info(self, kernel_count: bool = True) -> str:
info += _i18n("Jupyter Server {version} is running at:\n{url}").format(
version=ServerApp.version, url=self.display_url
)
if self.gateway_config.gateway_enabled:
info += (
_i18n("\nKernels will be managed by the Gateway server running at:\n%s")
% self.gateway_config.url
)
if hasattr(self.kernel_manager, "info"):
info += self.kernel_manager.info
return info

def server_info(self) -> dict[str, t.Any]:
Expand Down
11 changes: 11 additions & 0 deletions jupyter_server/services/kernels/kernelmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
Integer,
List,
TraitError,
Type,
Unicode,
default,
validate,
Expand All @@ -51,6 +52,8 @@
from jupyter_server import DEFAULT_EVENTS_SCHEMA_PATH
from jupyter_server._tz import isoformat, utcnow
from jupyter_server.prometheus.metrics import KERNEL_CURRENTLY_RUNNING_TOTAL
from jupyter_server.services.kernels.connection.base import BaseKernelWebsocketConnection
from jupyter_server.services.kernels.connection.channels import ZMQChannelsWebsocketConnection
from jupyter_server.utils import ApiPath, import_item, to_os_path


Expand Down Expand Up @@ -899,6 +902,14 @@ def _default_event_logger(self):
pass
return logger

websocket_connection_class = Type(
default_value=ZMQChannelsWebsocketConnection,
klass=BaseKernelWebsocketConnection,
help="""
The websocket connection class to use for this manager's kernels.
""",
).tag(config=True)

def emit(self, schema_id, data):
"""Emit an event from the kernel manager."""
self.event_logger.emit(schema_id=schema_id, data=data)
Expand Down
Loading
Loading