How it works...

This recipe makes use of channels, which are covered more extensively in Chapter 9, Parallelism and Concurrency. The signal.Notify function requires a channel to send signal notifications to and also the types of signal we care about. Then, we set up a function in a Go routine to handle any activity on the channel we passed to that function. Once we receive the signal, we can handle it however we want. We can terminate the application, respond with a message, and have different behaviors for different signals. The kill command is a good way to test passing signals to the applications.

We also use a done channel to block the application from terminating until a signal is received. Otherwise, the program would terminate immediately. This is unnecessary for long-running applications such as web applications. It can be very useful to create appropriate signal handling routines to perform cleanup, especially in applications with large amounts of Go routines that are holding a significant amount of state. A practical example of a graceful shutdown might be to allow current handlers to complete their HTTP requests without terminating them midway.