Graceful Shutdown Pattern in Go

16 March 2024

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")
}

comments powered by Disqus