SoFunction
Updated on 2025-03-04

How to achieve elegant shutdown in a Web service in Go

When building web services, we often encounter a difficult problem:When we want to stop the service, how do we ensure that the request being processed can be completed smoothly instead of a sudden interruption?This technology is called "elegant shutdown" and it ensures that all requests are handled properly when the service is shut down.

In this article, we will demonstrate how to use the Gin framework to achieve elegant shutdown in Go with a simple example.

What is elegant shutdown?

Elegant shutdown means that before shutting down the service, the service first handles the request currently being processed, and then shuts down the service. This ensures that the service will not lose the request and will not affect the request being processed. This approach can improve user experience and prevent data loss or inconsistency caused by service disruption. and executeCtrl + Corkill -2 pidThe command to close the service will not wait for the service to complete the request, which will cause the service to lose the request.

How to achieve elegant shutdown?

After Go version 1.8,Built-inShutdown()The method supports elegant shutdown.

Code implementation

Let's look at a specific code example. Through this example, we will show how to achieve elegant shutdown.

package main

import (
	"context"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"/gin-gonic/gin"
)

func main() {
	router := ()

	// Define a simple route	("/ping", func(c *) {
		// Simulate a time-consuming operation, such as a database query or external API call		(5 * )
		(, {
			"message": "pong",
		})
	})

	// Configure HTTP server	srv := &{
		Addr:    ":8080",
		Handler: router,
	}

	// Start the server	go func() {
		if err := (); err != nil && err !=  {
			("Failed to start server: %v", err)
		}
	}()

	// Wait for the interrupt signal to gracefully shut down the server, setting a 5-second timeout for the 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")

}

Code parsing

1. Routing definition and service startup

router := ()
("/ping", func(c *) {
	(5 * )
	(, {
		"message": "pong",
	})
})

First, we created a simple Gin route and defined a/pinginterface. When accessing this interface, the server simulates a 5-second operation and returns a JSON response. This code shows a typical scenario where an elegant shutdown may be required: the server may be processing time-consuming requests, and if it is shut down directly at this time, the request will be interrupted.

2. HTTP server configuration and startup

srv := &{
	Addr:    ":8080",
	Handler: router,
}

go func() {
	if err := (); err != nil && err !=  {
		("Failed to start server: %v", err)
	}
}()

We useThe structure is configured and started an HTTP server. The server runs in a separate goroutine so that the main program can continue to execute without waiting for the server to start.

3. Capture system signals

quit := make(chan , 1)
(quit, , )

<-quit

To achieve elegant shutdown, we need to capture the system signal. Used hereos/signalPacket to monitorandSignal. When the user pressesCtrl+COr bykillWhen the command sends signals, these signals are captured and sent toquitThe program will then resume from the blocking state and continue to execute subsequent code.

4. Achieve elegant shutdown

ctx, cancel := ((), 5*)
defer cancel()

if err := (ctx); err != nil {
	("Server Shutdown: ", err)
}

After capturing the shutdown signal, we useofShutdownMethod to achieve elegant shutdown.ShutdownMethod accepts acontextParameters, thiscontextSet a timeout time. Here, we set a 5-second timeout, meaning that the server will wait for the unfinished request to be processed within 5 seconds and then shut down. If the set timeout time is exceeded, the server will exit and the program will end normally.

How to verify the effect of elegant shutdown?

To verify the effect of elegant shutdown, follow these steps:

  • Open the terminal and run go run gin_shutdown.go
  • Open the browser and accesshttp://127.0.0.1:8080/pingAt this time, the browser should have a white screen waiting for the server to return a response
  • Quickly press the Ctrl+C command on the terminal you just opened, and the program will be automatically sent to the
  • At this time, the program will not exit immediately, but will wait for the above2The step response is returned and then exited, thus achieving the effect of elegant shutdown

Summarize

Elegant shutdown is an important technical point in building robust web services, which ensures that all requests being processed can be properly completed when the service is closed. In this article, we demonstrate how to achieve elegant shutdown in Go through the Gin framework. In this way, we can improve the user experience and reduce various potential problems caused by service outages.

This is the article about how Go language can achieve elegant shutdown in web services. For more relevant content on elegant Go, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!