jupyter_server icon indicating copy to clipboard operation
jupyter_server copied to clipboard

[Proposal] Jupyter Server should handle resolving kernel lifecycle and execution states.

Open Zsailer opened this issue 3 years ago • 6 comments

Frontend applications should be able to fetch the lifecycle states (starting, connecting, connected, terminating, dead, restarting, ...) and execution states (busy, idle, etc.) of a given kernel. The server should be in charge of resolving these states, since it talks directly to the kernel.

As mentioned in previous issue, today, frontends are forced to resolve the kernel states by tracking IOPub status messages. There are many problems with relying on the client to listen to the IOPub stream. See that issue for more details.

I propose that we make Jupyter Server's kernel manager responsible for storing, tracking, and returning the state of its kernel. We should add a REST API to the kernels service to fetch the state of a kernel, e.g.

GET /api/kernels/{kernel-id}/state

RESPONSE:
{
  "execution_state": "idle",
  "lifecycle_state": "connected"
}

We can also consider leveraging the Jupyter Event system to emit notifications with the kernel state changes.

This proposal would address #989

Zsailer avatar Sep 22 '22 21:09 Zsailer

It's probably out of scope for now, but I believe that it would be useful if in future kernels could provide progress updates (rather than simple idle/busy). The proposed response format seems easily extensible to include e.g. "execution_progress": 0.5 so +1.

I would say that for user experience the latency matters here so if implementation as an event means that there is no delay due to pooling in longer intervals it might be better (but I have no insight if that is the case).

krassowski avatar Sep 24 '22 18:09 krassowski

Coming back here from https://github.com/jupyterlab/jupyterlab/issues/16059. This proposal would solve https://github.com/jupyterlab/jupyterlab/issues/16059 (the kernel status could be properly updated after refresh), but it does not solve the problem of status for individual cells. I am talking about the execution indicators like [*] - these would still not show up even if we implement this proposal.

In https://github.com/jupyterlab/jupyterlab/issues/16059 I was thinking about storing the information about pending execution on frontend. Because a pending execution request may have been completed during page reload, frontend would need a way to ask the kernel (server?) about the status of that execution request (which can be identified by message id). This could be solved by extending the proposed jupyter-server API with:

GET /api/kernels/{kernel-id}/{execution-request-id}/state

jupyter-server would then keep track of the kernel status updates in a dictionary with binary values. Thoughts?

(and in future those could be made floats to represent progress ;))

krassowski avatar Mar 26 '24 11:03 krassowski

Going a step further, I think the long-term solution is having server-side execution, and not having frontends deal with the kernel protocol in the first place.

davidbrochart avatar Mar 26 '24 13:03 davidbrochart

Server-side execution as implemented in https://github.com/jupyterlab/jupyterlab/pull/15448 does not solve https://github.com/jupyterlab/jupyterlab/issues/16059 itself. I think these two solutions are working in lockstep.

krassowski avatar Mar 26 '24 16:03 krassowski

Not yet, but for instance https://github.com/jupyter-server/jupyter_ydoc/pull/197 goes in that direction. The cell execution state could be included in the notebook shared model, and the kernel execution state could be inferred from all cells' execution state.

davidbrochart avatar Mar 26 '24 16:03 davidbrochart

I think this is a reasonable idea to store these in the shared model.

In any case, I think we need more than execution_state: str. While it is nice that upon refresh cells would show up as busy/pending execution, when you get a new status from the kernel saying idle, how would you know which cell was it for?

What I am saying is that maybe we need to store a list of objects mapping to each of the pending execution requests. Something like:

class Cell:
   pending_requests: Request[]

class Request:
   id: str
   type: 'stdin_request' | 'execute_request' 

Now, execute_request and stdin_request are quite different, the former is sent from client to kernel, the latter is send from kernel to client, so I am not sure if we want to keep them together, but stdin_request is equally important because without a way of restoring the input box the kernel ends in a deadlock after refresh.

krassowski avatar Mar 27 '24 17:03 krassowski