Concept

Graceful Shutdown refers to the orderly termination of a program or service, ensuring that all resources are properly closed, ongoing tasks are completed, and data consistency and integrity are maintained. Unlike a forced exit (such as killing a process directly), a graceful shutdown prevents data loss, resource leaks, or inconsistent system states.

Steps

  1. Receive Exit Signals:

    The program needs to listen for system signals (e.g., SIGINT, SIGTERM) or custom exit requests to trigger the graceful shutdown process.

    Special Note: The SIGKILL signal triggered by kill -9 pid cannot be handled, as the process is forcibly terminated by the system. Therefore, avoid using this command to terminate the program; instead, use kill pid, which triggers SIGTERM.

  2. Stop Accepting New Requests:

    During the shutdown process, the program should stop accepting new requests or tasks to avoid processing incomplete work.

  3. Complete Ongoing Tasks:

    Ensure that all tasks or requests currently being processed are completed. For example, an HTTP server should wait for the current request to finish before shutting down.

  4. Release Resources:

    Close database connections, file handles, network connections, and other resources to ensure no resource leaks.

  5. Clean Up Temporary States:

    Clear caches, temporary files, or intermediate states to ensure system consistency.

  6. Timeout Mechanism:

    Set a timeout period. If the shutdown process cannot be completed within the specified time, force an exit to avoid the program hanging.

  7. Logging:

    Record key information during the shutdown process for troubleshooting purposes.

Implementation

 1func main() {
 2    go server.ListenAndServe()
 3    
 4    // Listen for exit signals
 5	sig := make(chan os.Signal, 1)
 6	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
 7    // Execute graceful shutdown upon receiving the signal
 8	<-sig
 9	logger.Info("Stopping the service...")
10    // Create a context with a 5-second timeout
11	shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
12	defer cancel()
13	
14    if err := server.Shutdown(shutdownCtx); err != nil {
15        logger.Info("shutdown err: %v", err)
16    }
17
18    logger.Info("Server gracefully shut down")
19}
FeatureHTTP Graceful ShutdowngRPC Graceful Shutdown
Stop Accepting RequestsCall http.Server.ShutdownCall grpc.Server.GracefulStop
Timeout ControlSupported (via context.WithTimeout)Not supported (requires manual implementation)
Streaming Connection HandlingNot applicableNeeds to wait for streaming RPC calls to finish
Underlying ProtocolHTTP/1.1 or HTTP/2Based on HTTP/2
Implementation ComplexityRelatively simpleMore complex (requires handling streaming connections)