Home > database >  Go signal handler doesn't handle terminal window closing
Go signal handler doesn't handle terminal window closing

Time:12-27

I have written a cli tool in go. When the cli tool is invoked via the terminal, i want the tool to wait for a Ctrl C interrupt(SIGINT) before calling a cleanup() function, before finally exiting.

however, as well as handling SIGINT, i also want the tool to handle cases where the terminal window is simply closed by the user. if its closed, i want the same cleanup function to be called. Here is a sample of what i tried.

package main

import (
    "fmt"
    "os"
    "syscall"
    "os/signal"
    "os/exec"
    "github.com/sirupsen/logrus"
)

func main() {
    // Parse the command-line argument.
    if len(os.Args) < 2 {
        logrus.Fatalf("Missing required argument")
    }
    arg := os.Args[1]

    logrus.Infof("Running with argument: %s", arg)

    // Set up signal handling.
    signals := make(chan os.Signal, 1)
    signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)

    done := make(chan bool, 1)
    go func() {
        sig := <-signals
        fmt.Println("")
        fmt.Println("Disconnection requested via Ctrl C", sig)
        done <- true
    }()

    logrus.Infof("Press Ctrl C to disconnect.")
    <-done

    cleanup()

    os.Exit(0)
}

func cleanup() {
    fmt.Println("Performing cleanup tasks...")
    touchFile := exec.Command("touch", "testfile.txt",)
    _, err := touchFile.CombinedOutput()

    if err != nil {
        println(err)
    }
}

This works for cases where the user sends an interrupt via Ctrl C and the cleanup function is called, but the cleanup function is never called when the user simply just closes the window. I though the inclusion of syscall.SIGHUP would work for this. please advise.

Edit: i've tested this in the default MacOS terminal, and the cleanup function is called when closing the window, but not when using iTerm.

CodePudding user response:

package main

import (
redacted
)

func main() {
    // Parse the command-line argument.
    if len(os.Args) < 2 {
        logrus.Fatalf("Missing required argument")
    }
    arg := os.Args[1]

    log.Infof("Running with argument: %s", arg)

    // Set up signal handling.
    signals := make(chan os.Signal, 1)
    signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)

    done := make(chan bool, 1)
    go func() {
        sig := <-signals
        fmt.Println("")
        fmt.Println("Disconnection requested via Ctrl C", sig)
        done <- true
    }()

    log.Infof("Press Ctrl C to disconnect.")
    <-done

    cleanup()

    os.Exit(0)
}

func cleanup() {
    fmt.Println("Performing cleanup tasks...")
    touchFile := exec.Command("touch", "testfile.txt",)
    _, err := touchFile.CombinedOutput()

    if err != nil {
        println(err)
    }
}

The addition of SIGKILL works now for iTerm.

  • Related