Skip to content

Commit

Permalink
Set interrupt_mode to message and handle interrupt_request.
Browse files Browse the repository at this point in the history
  • Loading branch information
janpfeifer committed Apr 7, 2024
1 parent 9ee7158 commit 6c87a1e
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 12 deletions.
5 changes: 5 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# GoNB Changelog

## Next

* [`interrupt_mode`] set to `message`, as opposed to having a `SIGINT`. Works both in JupyterLab and VSCode.
* Interrupt all cell executions at `shutdown_request`.

## 0.10.0, 2024/04/07 Improvements on Plotly, VSCode support, interrupt handling and several minor fixes.

* Added special cell commands ("magic"):
Expand Down
10 changes: 10 additions & 0 deletions internal/dispatcher/dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,15 @@ func handleShellMsg(msg kernel.Message, goExec *goexec.State) (err error) {
err = errors.WithMessagef(err, "replying 'shutdown_request'")
}

case "interrupt_request":
// Interrupt current cell being executed if any.
klog.V(2).Infof("Received interrupt_request.")
msg.Kernel().CallInterruptSubscribers()
replyContent := make(map[string]any)
replyContent["status"] = "ok"
err = msg.Reply("interrupt_reply", replyContent)
klog.V(2).Infof("Replied with interrupt_reply.")

default:
// Log, ignore, and hope for the best.
klog.Infof("Unhandled shell-socket message %q", msg.ComposedMsg().Header.MsgType)
Expand Down Expand Up @@ -226,6 +235,7 @@ func handleBusyMessage(msg kernel.Message, goExec *goexec.State) (err error) {
// handleShutdownRequest sends a "shutdown" message.
func handleShutdownRequest(msg kernel.Message, goExec *goexec.State) error {
klog.Info("Shutting down in response to shutdown_request")
msg.Kernel().CallInterruptSubscribers() // Interrupt current runs.

content := msg.ComposedMsg().Content.(map[string]any)
replyContent := make(map[string]any)
Expand Down
21 changes: 13 additions & 8 deletions internal/kernel/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ var logoSVG []byte
// jupyterKernelConfig is the Jupyter configuration to be
// converted to a `kernel.json` file under `~/.local/share/jupyter/kernels/gonb`
// (or `${HOME}/Library/Jupyter/kernels/` in Macs)
// See details in: https://jupyter-client.readthedocs.io/en/latest/kernels.html#kernelspecs
type jupyterKernelConfig struct {
Argv []string `json:"argv"`
DisplayName string `json:"display_name"`
Language string `json:"language"`
Env map[string]string `json:"env"`
Argv []string `json:"argv"`
DisplayName string `json:"display_name"`
Language string `json:"language"`
InterruptMode string `json:"interrupt_mode"`
Env map[string]string `json:"env"`
}

// Install gonb in users local Jupyter configuration, making it available. It assumes
Expand All @@ -40,16 +42,19 @@ type jupyterKernelConfig struct {
// the kernel configuration, and that copy is used.
//
// If forceDeps is true, installation will succeed even with missing dependencies.
//
// Documentation: https://jupyter-client.readthedocs.io/en/latest/kernels.html#kernelspecs
func Install(extraArgs []string, forceDeps, forceCopy bool) error {
gonbPath, err := os.Executable()
if err != nil {
return errors.Wrapf(err, "Failed to find path to GoNB binary")
}
config := jupyterKernelConfig{
Argv: []string{gonbPath, "--kernel", "{connection_file}"},
DisplayName: "Go (gonb)",
Language: "go",
Env: make(map[string]string),
Argv: []string{gonbPath, "--kernel", "{connection_file}"},
DisplayName: "Go (gonb)",
Language: "go",
InterruptMode: "message", // "message" (a `interrupt_request` is sent) or "signal" (using SIGINT signal)
Env: make(map[string]string),
}
if len(extraArgs) > 0 {
config.Argv = append(config.Argv, extraArgs...)
Expand Down
8 changes: 4 additions & 4 deletions internal/kernel/kernel.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func (k *Kernel) HandleInterrupt() {
select {
case sig := <-k.signalsChan:
k.Interrupted.Store(true)
k.callInterruptSubscribers()
k.CallInterruptSubscribers()
klog.Infof("Signal %s received.", sig)
if sig == os.Interrupt {
// Simply interrupt running cells.
Expand Down Expand Up @@ -245,9 +245,9 @@ func (k *Kernel) UnsubscribeInterrupt(id SubscriptionId) {
}
}

// callInterruptSubscribers in a separate goroutine each.
// Meant to be called when JupyterServer sends a kernel interrupt (either a SIGINT, or a message to interrupt).
func (k *Kernel) callInterruptSubscribers() {
// CallInterruptSubscribers in a separate goroutine each.
// Meant to be called when JupyterServer sends a kernel interrupt (either a SIGINT, or a `interrupt_request` message to interrupt).
func (k *Kernel) CallInterruptSubscribers() {
k.muSubscriptions.Lock()
defer k.muSubscriptions.Unlock()

Expand Down

0 comments on commit 6c87a1e

Please sign in to comment.