Preface
After the web project we wrote is deployed, the service will often be restarted because of configuration changes or function iterations. The simple kill -9 pid method will force the process to be shut down, which will cause the request currently being processed by the server to fail. Is there a more elegant way to shut down or restart?
Reading this article requires understanding some concepts of signals in UNIX systems. Please check the information in advance to preview.
Turn off the machine gracefully
What is elegant shutdown?
Elegant shutdown means that the server shutdown command is not shut down immediately after it is issued, but waits for all the requests currently being processed before exiting the program. It is a client-friendly shutdown method. and executeCtrl+C
When closing the server, the process will be forced to end, causing problems with the request being accessed.
How to achieve elegant shutdown?
After Go version 1.8, built-inShutdown()The method supports elegant shutdown, the specific examples are as follows:
// +build go1.8 package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "/gin-gonic/gin" ) func main() { router := () ("/", func(c *) { (5 * ) (, "Welcome Gin Server") }) srv := &{ Addr: ":8080", Handler: router, } go func() { // Turn on a goroutine startup service if err := (); err != nil && err != { ("listen: %s\n", err) } }() // Wait for the interrupt signal to gracefully shut down the server, setting a 5-second timeout for shutdown operation quit := make(chan , 1) // Create a channel to receive signals // kill will send a signal by default // kill -2 send signal, our commonly used Ctrl+C is to trigger the system SIGINT signal // kill -9 sends a signal, but cannot be captured, so it does not need to be added // Forward the received or signal to quit (quit, , ) // It won't block here <-quit // Blocking is here, and the above two signals will be executed only when the above two signals are received. ("Shutdown Server ...") // Create a 5-second timeout context ctx, cancel := ((), 5*) defer cancel() // Elegantly close the service within 5 seconds (process unprocessed requests before closing the service), and exit after more than 5 seconds if err := (ctx); err != nil { ("Server Shutdown: ", err) } ("Server exiting") }
How to verify the effect of elegant shutdown?
After the above code is run, a web service will be opened on the local port 8080, and it only registers one route./
, the backend service will sleep for 5 seconds before returning the response information.
When we press Ctrl+C, we will send it to notify the program to shut down gracefully. The specific method is as follows:
- Open the terminal, compile and execute the above code
- Open a browser and visit 127.0.0.1:8080/. At this time, the browser white screen is waiting for the server to return a response.
- Execute quickly in the terminal
Ctrl+C
Send commands to the programSignal
- At this time, the program does not exit immediately, but waits for our response in step 2 to return before exiting, thereby achieving elegant shutdown.
Restart gracefully
Elegant shutdown has been achieved, so how to achieve elegant restart?
We can usefvbock/endlessTo replace the defaultListenAndServe
Start the service to implement it, the sample code is as follows:
package main import ( "log" "net/http" "time" "/fvbock/endless" "/gin-gonic/gin" ) func main() { router := () ("/", func(c *) { (5 * ) (, "hello gin!") }) // The default endless server will listen to the following signals: //, syscall.SIGUSR1, syscall.SIGUSR2, and // Received SIGHUP signal will trigger `fork/restart` to achieve elegant restart (kill -1 pid will send SIGHUP signal) // Received or signal will trigger elegant shutdown // Receiving the SIGUSR2 signal will trigger HammerTime // SIGUSR1 and SIGTSTP are used to trigger some user-defined hook functions if err := (":8080", router); err!=nil{ ("listen: %s\n", err) } ("Server exiting") }
How to verify the effect of elegant restart?
We performkill -1 pid
Command sendTo notify the program to restart gracefully, the specific methods are as follows:
- Open the terminal, go build -o graceful_restart compile and execute./graceful_restart, the terminal outputs the current pid (assuming it is 43682)
- Returns the request function in the code
hello gin!
Modified tohello q1mi!
, compile go build -o graceful_restart - Open a browser and visit 127.0.0.1:8080/. At this time, the browser white screen is waiting for the server to return a response.
- Quickly execute kill -1 43682 command in the terminal to send a signal to the program
- Wait for Step 3 Browser to receive the response message
hello gin!
After accessing 127.0.0.1:8080 again/will receive ithello q1mi!
response. - The replacement of program code is completed without affecting the currently unprocessed request, achieving an elegant restart.
But it should be noted that the PID of the program has changed at this time, becauseendless
It is throughfork
The child process handles a new request and then exits after the original process has processed the current request. So when your project is using something likesupervisor
This method is not applicable when managing the software process.
Summarize
Whether it is an elegant shutdown or an elegant restart, it is ultimately a by listening to a specific system signal and then performing certain logical processing to ensure that the request being processed by the current system is processed normally before closing the current process. Whether to use elegant shutdown or elegant restart and how to achieve it depends on the actual situation of the project.
The above is the detailed content on how to elegantly shut down or restart golang. For more information about golang shutdown and restart, please follow my other related articles!