SoFunction
Updated on 2025-03-03

How to elegantly shut down or restart operations using golang

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+CWhen 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 terminalCtrl+CSend 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 defaultListenAndServeStart 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 pidCommand 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 codehello 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 messagehello 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, becauseendlessIt is throughforkThe 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 likesupervisorThis 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!