Handling CTRL-C (interrupt signal) in Golang Programs

Interruptions

Recently I’ve been working on a Go program where I will need to do some cleanup work before exiting if the users press CTRL+C (thereby sending an interrupt signal, SIGINT, to the process). I was unsure of how to do this.

As it turns out, signal.Notify is the method by which this is accomplished.

Here is some sample source code:

// Code to set up some services up here...

// After setting everything up!
// Wait for a SIGINT (perhaps triggered by user with CTRL-C)
// Run cleanup when signal is received
signalChan := make(chan os.Signal, 1)
cleanupDone := make(chan struct{})
signal.Notify(signalChan, os.Interrupt)
go func() {
    <-signalChan
    fmt.Println("\nReceived an interrupt, stopping services...\n")
    cleanup(services, c)
    close(cleanupDone)
}()
<-cleanupDone

I like this example because it really illuminates the power of Go’s concurrency primitives. Instead of having to worry about complicated process or threading logic I simply abstract away the concurrency details using a goroutine and a couple of channels. In this instance, the main goroutine is blocked by an unbuffered cleanupDone channel because that is the behavior that is expected (we’ve already spun up additional goroutines earlier to do some logging and handling outside of the context of the main goroutine).

Now I can clean up after my containers when a user interrupts the terminal with CTRL+C. Awesome!

Until next time, stay sassy Internet.

  • Nathan