Handling Unix Signals in Go

GoGoBeginner
Practice Now

This tutorial is from open-source community. Access the source code

Introduction

The Signals lab demonstrates how to handle Unix signals in Go programs using channels.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL go(("`Go`")) -.-> go/NetworkingGroup(["`Networking`"]) go/NetworkingGroup -.-> go/signals("`Signals`") subgraph Lab Skills go/signals -.-> lab-15505{{"`Handling Unix Signals in Go`"}} end

Signals

In some cases, we want our Go programs to handle Unix signals intelligently. For instance, we might want a server to shut down gracefully when it receives a SIGTERM, or a command-line tool to stop processing input if it receives a SIGINT.

  • Create a buffered channel to receive os.Signal notifications.
  • Register the channel to receive notifications of specified signals using signal.Notify.
  • Create a goroutine to execute a blocking receive for signals.
  • Print out the received signal and notify the program that it can finish.
  • Wait for the expected signal and then exit.
## When we run this program it will block waiting for a
## signal. By typing `ctrl-C` (which the
## terminal shows as `^C`) we can send a `SIGINT` signal,
## causing the program to print `interrupt` and then exit.
$ go run signals.go
awaiting signal
^C
interrupt
exiting

There is the full code below:

// Sometimes we'd like our Go programs to intelligently
// handle [Unix signals](https://en.wikipedia.org/wiki/Unix_signal).
// For example, we might want a server to gracefully
// shutdown when it receives a `SIGTERM`, or a command-line
// tool to stop processing input if it receives a `SIGINT`.
// Here's how to handle signals in Go with channels.

package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"
)

func main() {

	// Go signal notification works by sending `os.Signal`
	// values on a channel. We'll create a channel to
	// receive these notifications. Note that this channel
	// should be buffered.
	sigs := make(chan os.Signal, 1)

	// `signal.Notify` registers the given channel to
	// receive notifications of the specified signals.
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	// We could receive from `sigs` here in the main
	// function, but let's see how this could also be
	// done in a separate goroutine, to demonstrate
	// a more realistic scenario of graceful shutdown.
	done := make(chan bool, 1)

	go func() {
		// This goroutine executes a blocking receive for
		// signals. When it gets one it'll print it out
		// and then notify the program that it can finish.
		sig := <-sigs
		fmt.Println()
		fmt.Println(sig)
		done <- true
	}()

	// The program will wait here until it gets the
	// expected signal (as indicated by the goroutine
	// above sending a value on `done`) and then exit.
	fmt.Println("awaiting signal")
	<-done
	fmt.Println("exiting")
}

Summary

The Signals lab demonstrates how to handle Unix signals in Go programs using channels. By creating a buffered channel to receive os.Signal notifications and registering the channel to receive notifications of specified signals using signal.Notify, we can gracefully handle signals and exit the program when the expected signal is received.

Other Go Tutorials you may like