kernel_gateway icon indicating copy to clipboard operation
kernel_gateway copied to clipboard

jupyter websocket messages not updating UI

Open dlcrista opened this issue 3 years ago • 5 comments

I'm wondering how does the frontend know what cellId each cell is? If I make a call to /api/contents/myfile.ipynb?content=1 , no cellId appears on the returned file contents model.

When I inspect the wss message that is sent from the frontend upon clicking the execute button in the UI (through the dev tools), I can see that the structure of the message is as follows:

{
    "header": {
        "username": "",
        "version": "5.2",
        "msg_type": "execute_request",
        "session": "some uuid1",
        "msg_id": "some uuid2"
    },
    "metadata": {
        "cellId": "some uuid3",
        "deletedCells": []
    },    
    "parent_header": {},
    "channel": "shell",
    "content": {
        "silent": false,
        "store_history": true,
        "user_expressions": {},
        "allow_stdin": true,
        "stop_on_error": true,
        "code": "print(\"doge\")"
    },
    "buffers": []
}

When I refresh the page, the cellId for the same cell is always different. How is it tied to the UI's cells?

I know that the session id is received upon making a get request to /api/kernels/{kernel_id}/channels and from the docs, msg_id seems to be randomly created from str(uuid.uuid4()) but how do cells become tied to particular ids? The only way I can get my code to appear under a cell in the UI is if I reuse the same msg_id that the frontend created upon clicking the run button on the UI (and if I do that, then session and cellId can be empty since I guess it's inferred from the msg_id)

Not sure if this is the right place to ask this question, if not, please point me in the correct direction. Thanks


Edit: From snooping around the UI, it looks like the model has a cellId. I have not verified manually trying to get the cellId through python or javascript

(function (CodeCell) {
    /**
     * Execute a cell given a client session.
     */
    function execute(cell, session, metadata) {
        let model = cell.model;
        let code = model.value.text;
        if (!code.trim() || !session.kernel) {
            model.executionCount = null;
            model.outputs.clear();
            return Promise.resolve(void 0);
        }
        let cellId = { cellId: model.id };
        metadata = Object.assign({}, metadata, cellId);
        model.executionCount = null;
        cell.outputHidden = false;
        cell.setPrompt('*');
        model.trusted = true;
        return outputarea_1.OutputArea.execute(code, cell.outputArea, session, metadata)
            .then(msg => {
            model.executionCount = msg.content.execution_count;
            return msg;
        })
            .catch(e => {
            if (e.message === 'Canceled') {
                cell.setPrompt('');
            }
            throw e;
        });
    }
    CodeCell.execute = execute;
})(CodeCell = exports.CodeCell || (exports.CodeCell = {}));

dlcrista avatar Sep 22 '21 23:09 dlcrista

When using nbformat 4.5+, each cell has an id field that contains a "unique" value. I suspect the cellId in the kernel message is derived from that.

{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "0584ae61",
   "metadata": {},
   "outputs": [],
   "source": [
    "i=4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "8963b4cb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n"
     ]
    }
   ],
   "source": [
    "print(i)"
   ]
}

I don't see the id field in the cells of notebooks with nbformat < 4.5, so you might check which format version you're using.

kevin-bates avatar Sep 30 '21 18:09 kevin-bates

Whenever you refresh the page, you'll notice that the cellId in the websocket message is different, even if it's technically the same cell. This would imply that there's no relation with the cellId in the websocket message and the cellId in the cell field.

dlcrista avatar Sep 30 '21 19:09 dlcrista

ok. It could also imply there's a "disconnect" on some level with a gateway involved. Do you see the same behavior when not going through the gateway?

kevin-bates avatar Sep 30 '21 21:09 kevin-bates

So just to get some terms in sync, the gateway is the wss channel? That connects from the UI automatically

dlcrista avatar Oct 05 '21 18:10 dlcrista

I would say the gateway is a "kernel as a service" model. It has both HTTP and WSS APIs. All kernel interactions - whether that be for the kernel's lifecycle management (start, stop, interrupt, restart) or code execution (via websocket) are forwarded to the gateway from the notebook server when the gateway is configured. Otherwise, those same interactions occur locally (within the notebook server). The UI always goes through the notebook server to interact with the kernel.

Of course, custom UIs can be built to interact with the gateway directly, but Notebook/Lab always go through their respective servers, and that server redirects to the gateway (when configured to do so).

kevin-bates avatar Oct 05 '21 18:10 kevin-bates