How to signal shutdown by user code?
I'm implementing a kernel by inheriting from ipykernel.kernelbase.Kernel, as described at Making simple Python wrapper kernels.
My do_execute method passes code to an external interpreter implemented in a Python module, and it is possible that this code includes an instruction to shut down the interpreter, comparable to sys.exit(0) in Python. When that happens, the interpreter raises an exception.
Because after that code the interpreter is no longer usable, I want to catch that exception and in response initiate a kernel shutdown. Unfortunately, I wasn't able to figure out how to do so.
Is it possible to initiate a kernel shutdown from within the kernel? If yes, how?
If not, what is the recommended way to deal with code which shuts down the interpreter? Detecting that from the code might be impossible to do correctly. And even if I could do it, I would still have to initiate shutdown from within do_execute.
I found a solution: I was able to detect the execution of an instruction to shut down the interpreter, but only afterwards, because the Python interface to the interpreter throws an Exception.
I still don't know how to trigger a shutdown, and would still be interested how to do so, but for the moment I settled for restarting the interpreter and sending a message to the user.
If you're extending KernelBase, would do_shutdown with restart=False not satisfy this?
https://github.com/ipython/ipykernel/blob/5b4b7a0c07c48742ac17c60cbd2d6a13d09e29c2/ipykernel/kernelbase.py#L996-L1000
@jjvraw, I have implemented do_shutdown. But as the docstring says, this is "to do things when the frontend shuts down the kernel", i.e. cleanup actions.
I'm looking for a way to initiate a shutdown from the kernel, within do_execute. Basically, how the kernel can make the frontend to shut down the kernel, thereby calling do_shutdown?
do_shutdown is really the logic that would be called if the user tries to shutdown from the client.
how the kernel can make the frontend to shut down the kernel
The kernel cannot know how many clients there are and knows nothing about the clients actually. So it cannot request anything to any client.
What you can do is kill the process yourself from code though. According to the messaging protocol it's considered a valid shutdown if the user typed "quit" in code. So you can do it under the conditions you want.
The clients will then be notified that the kernel is not responding anymore and they would need to restart it from the UI themselves.
@martinRenou
What you can do is kill the process yourself from code though. According to the messaging protocol it's considered a valid shutdown if the user typed "quit" in code. So you can do it under the conditions you want.
Are you referring to the "Note" under "Kernel shutdown"?
I think I tried that. However, it did not lead to a clean exit in Jupyter Console and Jupyter QtConsole.
What I'm looking for is that: The user sends code which includes "quit", and in response Jupyter Console / Jupyter QtConsole exits cleanly.
Ah, apologies @allefeld. I tried a less involved approach compared to @martinRenou's suggestion. If one can implement execute_request and catch the exception of the interpreter:
def execute_request(self, stream, ident, parent):
try:
return super().execute_request(stream, ident, parent)
catch SomeException:
parent['content']['restart'] = False
return super().shutdown_request(stream, ident, parent)
the kernel will shutdown.
However, as @martinRenou said
The kernel cannot know how many clients there are and knows nothing about the clients actually. So it cannot request anything to any client.
If the front-end is not expecting the kernel to shutdown, there will be some form of rejection/manual handling from the unexpected behavior.
This is my understanding as of now, at least. Best of luck !
@jjvraw, thanks for the tip, I will try that!