Hi All,
I’m building a web python ‘notebook’ that would execute python code against a remote iPython kernel.
I am running to issues with communicating to the remote kernel from my custom front-end.
For development, I have both front-end (web notebook) and ipython kernel running in local. iPython kernel is deployed and running in a docker container. Front-end is a simple nodejs program that uses zeroMQ to send requests to iPython kernel. I have studied the messaging protocol and understand that the python code to be executed has to sent as msg type ‘execute_request’ and the response would be of msg type ‘execute_reply’.
I’m able to send a valid ‘execute_request’ after signing the message but the response I receive is blank. Though I can see that the remote iPython kernel generating the ‘execute_reply’ message.
ipython kernel log:
[IPKernelApp] Created profile dir: '/home/myuser/.ipython/profile_default'
[IPKernelApp] Searching path ['/home/myuser/.ipython/profile_default', '/usr/etc/ipython', '/usr/local/etc/ipython', '/etc/ipython'] for config files
[IPKernelApp] Attempting to load config file: ipython_config.py
[IPKernelApp] Looking for ipython_config in /etc/ipython
[IPKernelApp] Looking for ipython_config in /usr/local/etc/ipython
[IPKernelApp] Looking for ipython_config in /usr/etc/ipython
[IPKernelApp] Looking for ipython_config in /home/myuser/.ipython/profile_default
[IPKernelApp] Attempting to load config file: ipython_kernel_config.py
[IPKernelApp] Looking for ipython_kernel_config in /etc/ipython
[IPKernelApp] Looking for ipython_kernel_config in /usr/local/etc/ipython
[IPKernelApp] Looking for ipython_kernel_config in /usr/etc/ipython
[IPKernelApp] Looking for ipython_kernel_config in /home/myuser/.ipython/profile_default
[IPKernelApp] Loading connection file /home/myuser/connection-file.json
[IPKernelApp] Starting the kernel at pid: 1
[IPKernelApp] shell ROUTER Channel on port: 39807
[IPKernelApp] stdin ROUTER Channel on port: 45359
[IPKernelApp] control ROUTER Channel on port: 40673
[IPKernelApp] iopub PUB Channel on port: 41097
[IPKernelApp] Heartbeat REP Channel on port: 49695
[IPKernelApp] Writing connection file: /home/myuser/connection-file.json
[IPKernelApp] To connect another client to this kernel, use:
[IPKernelApp] --existing /home/myuser/connection-file.json
NOTE: When using the `ipython kernel` entry point, Ctrl-C will not work.
To exit, you will have to explicitly quit this process, by either sending
"quit" from a client, or using Ctrl-\ in UNIX-like environments.
To read more about this, see https://github.com/ipython/ipython/issues/2049
To connect another client to this kernel, use:
--existing /home/myuser/connection-file.json
[IPKernelApp] Seeing logger to stderr, rerouting to raw filedescriptor.
[IPKernelApp] Loading IPython extensions...
[IPKernelApp] Loading IPython extension: storemagic
[IPKernelApp]
*** MESSAGE TYPE:execute_request***
[IPKernelApp] Content: {'code': 'print("Hello world!")', 'silent': False, 'store_history': True, 'user_expressions': {}, 'allow_stdin': False, 'stop_on_error': True}
--->
[IPKernelApp] execute_request: {'header': {'msg_id': 'db3792b4-0728-405c-9cac-5347b2724ad6', 'msg_type': 'execute_request', 'date': datetime.datetime(2022, 8, 4, 22, 40, 14, 903096, tzinfo=datetime.timezone.utc), 'version': '5.0'}, 'msg_id': 'db3792b4-0728-405c-9cac-5347b2724ad6', 'msg_type': 'execute_request', 'parent_header': {}, 'metadata': {}, 'content': {'code': 'print("Hello world!")', 'silent': False, 'store_history': True, 'user_expressions': {}, 'allow_stdin': False, 'stop_on_error': True}, 'buffers': []}
[IPKernelApp] {'header': {'msg_id': '7ed44e24-674afba1bf1df2f4a224aff3_1_5', 'msg_type': 'execute_reply', 'username': 'username', 'session': '7ed44e24-674afba1bf1df2f4a224aff3', 'date': datetime.datetime(2022, 8, 4, 22, 40, 14, 917864, tzinfo=datetime.timezone.utc), 'version': '5.3'}, 'msg_id': '7ed44e24-674afba1bf1df2f4a224aff3_1_5', 'msg_type': 'execute_reply', 'parent_header': {'msg_id': 'db3792b4-0728-405c-9cac-5347b2724ad6', 'msg_type': 'execute_request', 'date': datetime.datetime(2022, 8, 4, 22, 40, 14, 903096, tzinfo=datetime.timezone.utc), 'version': '5.0'}, 'content': {'status': 'ok', 'execution_count': 1, 'user_expressions': {}, 'payload': []}, 'metadata': {'started': datetime.datetime(2022, 8, 4, 22, 40, 14, 904511, tzinfo=datetime.timezone.utc), 'dependencies_met': True, 'engine': 'aac4c779-9b2d-4ec6-a932-7c230c31e6e6', 'status': 'ok'}, 'tracker': <zmq.sugar.tracker.MessageTracker object at 0x7f9a3468a890>}
[IPKernelApp]
*** MESSAGE TYPE:execute_request***
[IPKernelApp] Content: {'code': 'print("Hello world!")', 'silent': False, 'store_history': True, 'user_expressions': {}, 'allow_stdin': False, 'stop_on_error': True}
--->
This is my nodejs program:
const zmq = require("zeromq");
const crypto = require("crypto");
const { v4: uuidv4 } = require('uuid');
const shell_socket = zmq.socket('dealer');
let shell_addr = "tcp://localhost:39807";
console.log("\nConnecting shell socket at " + shell_addr + "...");
shell_socket.connect(shell_addr);
shell_socket.on("message", function(msg){
console.log("\nShell socket says:\n");
console.log("output:", msg.toString())
});
let key = <key>;
let header = {"msg_id": uuidv4(), "msg_type": "execute_request"};
let parent_header = {};
let metadata = {};
let content = {'code': 'print("Hello world!)")',
'silent': false,
'store_history': true,
'user_expressions': {},
'allow_stdin': false,
'stop_on_error': true };
let sign = JSON.stringify(header)
+ JSON.stringify(parent_header)
+ JSON.stringify(metadata)
+ JSON.stringify(content);
let hmac_digest = crypto.createHmac("sha256", key).update(sign).digest("hex");
shell_socket.send(["","<IDS|MSG>",hmac_digest,
JSON.stringify(header),
JSON.stringify(parent_header),
JSON.stringify(metadata),
JSON.stringify(content)]);
Output:
~/workspace/web_notebook$ node index.js
Connecting shell socket at tcp://localhost:39807...
Shell socket says:
output:
I am not able to figure out what I’m doing wrong. Could someone guide me or point to any resource that can help? I looked online for a working example but nothing exists for a non python client.
I have tried both ‘req’ and ‘dealer’ socket with zeroMQ and the behavior is the same.
Note: Using jupyter console pointed to the remote kernel in the same setup works fine.
/workspace/web_notebook$ jupyter console --existing connection-file.json
Jupyter console 6.4.4
Python 3.10.4 (main, Jun 29 2022, 12:14:53) [GCC 11.2.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.4.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: print("Hello world!")
Hello world!
In [2]:
connection-file.json
{
"shell_port": 39807,
"iopub_port": 41097,
"stdin_port": 45359,
"control_port": 40673,
"hb_port": 49695,
"ip": "0.0.0.0",
"key": <key>,
"transport": "tcp",
"signature_scheme": "hmac-sha256",
"kernel_name": ""
}