The following is an example of a graceful shutdown pattern I like to use in my Go applications which upon pressing Ctrl+C
to quit allows for performing clean-up tasks.
After running the application pressing Ctrl+C
sends an interrupt signal triggering a shutting down state. The shutting down state is used to clean up anything and has a defined timer limit. The application exists after either completing all shutting down tasks before the timer expires, the shutting down timer expires, or another Ctrl-C
interrupt is issued to force the shutdown.
func main() {
logger := log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime)
// Create context that listens for the interrupt signal from the OS
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
log.Print("Application is running")
// Listen for the interrupt signal
<-ctx.Done()
// Restore default behavior on the interrupt signal and notify user of shutdown
stop()
logger.Println("shutting down gracefully, press Ctrl+C again to force")
// The context is used to inform the application it has 5 seconds to finish any tasks
_, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Handle cleanup here if any
logger.Println("simulating cleanup work")
time.Sleep(3*time.Second)
logger.Println("Application exited")
}