ipykernel icon indicating copy to clipboard operation
ipykernel copied to clipboard

How to signal shutdown by user code?

Open allefeld opened this issue 2 years ago • 7 comments

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.

allefeld avatar Oct 02 '23 12:10 allefeld

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.

allefeld avatar Oct 04 '23 05:10 allefeld

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 avatar Dec 02 '23 16:12 jjvraw

@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?

allefeld avatar Dec 04 '23 15:12 allefeld

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 avatar Dec 04 '23 15:12 martinRenou

@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.

allefeld avatar Dec 04 '23 15:12 allefeld

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 avatar Dec 04 '23 20:12 jjvraw

@jjvraw, thanks for the tip, I will try that!

allefeld avatar Dec 04 '23 20:12 allefeld