Golang优雅的停止程序

I wish I could be more like you.

To shutdown go application gracefully, you can use open source libraries or write your own code.

Following are popular libraries to stop go application gracefully

https://github.com/tylerb/graceful
https://github.com/braintree/manners

In this article, I will explain how to write your own code to stop go app gracefully

Step 1

make channel which can listen for signals from OS. Refer os.Signal package for more detail. os.Signal package is used to access incoming signals from OS.

1
var gracefulStop = make(chan os.Signal)

Step 2

Use notify method of os.Signal to register system calls. For gracefully stop. we should listen to SIGTERM and SIGINT. signal.Notify method takes two arguments 1. channel 2. constant from syscall.

1
2
signal.Notify(gracefulStop, syscall.SIGTERM)
signal.Notify(gracefulStop, syscall.SIGINT)

Step 3

Now, We needs to create Go routine to listen channel “gracefulStop” for incoming signals. the following Go routine will block until it receives signals from OS. Now, you can perform clean up your stuff it can be closing DB connections, clearing buffered channels, write something to file, etc.. In the following code, I just put wait for 2 seconds. After completing your work you need to send a signal to OS by using os.Exit function. os.Exit function takes integer argument normally, it can be 0 or 1. 0 means clean exit without any error or problem. 1 means exit with an error or some issue. The exit status will help caller to identify the last status when process end.

1
2
3
4
5
6
7
go func() {
sig := <-gracefulStop
fmt.Printf("caught sig: %+v", sig)
fmt.Println("Wait for 2 second to finish processing")
time.Sleep(2*time.Second)
os.Exit(0)
}()

Full Source

For the demo, I use simple HTTP server which will display “Server is running” message on the browser.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main
import (
"os"
"os/signal"
"syscall"
"fmt"
"time"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w,"Server is running")
})
var gracefulStop = make(chan os.Signal)
signal.Notify(gracefulStop, syscall.SIGTERM)
signal.Notify(gracefulStop, syscall.SIGINT)
go func() {
sig := <-gracefulStop
fmt.Printf("caught sig: %+v", sig)
fmt.Println("Wait for 2 second to finish processing")
time.Sleep(2*time.Second)
os.Exit(0)
}()
http.ListenAndServe(":8080",nil)
}

https://kpbird.medium.com/golang-gracefully-stop-application-23c2390bb212
https://pkg.go.dev/syscall#SIGINT
http://husobee.github.io/golang/ecs/2016/05/19/ecs-graceful-go-shutdown.html4
https://pkg.go.dev/net/http#Server.Shutdown