Ctrl+C
famously terminates a program. By default in Go any running code is immediately stopped. But sometimes, you want to do a bit of clean-up before the program ends and this is especially elegant if you use the context.Context
package.
Pressing Ctrl+C
actually causes a signal to be sent to your program; the SIGINT
signal to be precise — referred to in Go as os.Interrupt
.
If you use context.Context
to handle cancellation throughout your program, then calling the CancelFunc
in the main function can trigger a graceful cascade of shutdown across your program.
The following code illustrates how to do this:
First, we create a global context with context.Background
before using context.WithCancel
to get a cancellation function: we can call this function to cancel the operations of the program.
Next, we trap the SIGINT
signal so we can run some code in response to it. The signal.Notify
function asks that any of the specified signals (in our case just os.Interrupt
) be sent down the channel c
rather then just immediately terminating the program.
We then defer a clean-up function that will run when the function is finished; it stops receiving the signals (via signal.Stop
) and calls the cancel
function to cancel the context.
In a separate goroutine (notice go func()
) we then use select
to wait for either a signal on the c
channel, or for the context itself to finish. Execution will block here waiting for one of those two things to happen before continuing. If we receive a signal on the c
channel, then we cancel the context by calling the cancel
function. In the case that the context cancels for other reasons (like a timeout, or whatever) this goroutine is cleaned up as the<-ctx.Done():
case will hit and return.
Multiple calls to cancel
are ok, after the first one they’re just no-ops.
What next?
Check out Francesc Campoy’s video about how to use context: