Golang 實現程序優雅退出的方法有哪些?

在 Go 語言中,實現程序的優雅退出是一項重要的任務,特別是在涉及到 HTTP 服務器、gRPC 服務器、以及其他後臺工作的情況下。以下是一些常見的平滑關閉方法:

1. HTTP Server 平滑關閉

Go 1.8 及以上版本提供了 http.Server 結構的 Shutdown 方法,用於平滑關閉 HTTP 服務器。

package main

import (
    "context"
    "net/http"
    "os"
    "os/signal"
    "time"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, World!"))
    })

    server := &http.Server{
        Addr:    ":8080",
        Handler: mux,
    }

    go func() {
        if err := server.ListenAndServe(); err != nil {
            if err != http.ErrServerClosed {
                // 處理監聽失敗的錯誤
            }
        }
    }()

    // 等待中斷信號來優雅地關閉服務器
    stop := make(chan os.Signal, 1)
    signal.Notify(stop, os.Interrupt)

    <-stop // 等待中斷信號
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    if err := server.Shutdown(ctx); err != nil {
        // 處理關閉服務器時的錯誤
    }
}

2. gRPC Server 平滑關閉

gRPC 服務器的平滑關閉可以通過 GracefulStop 方法實現。

package main

import (
    "context"
    "fmt"
    "net"
    "os"
    "os/signal"

    "google.golang.org/grpc"
    "google.golang.org/grpc/reflection"
)

type Greeter struct{}

func (s *Greeter) SayHello(ctx context.Context, in *HelloRequest) (*HelloReply, error) {
    return &HelloReply{Message: "Hello " + in.Name}, nil
}

func main() {
    listener, err := net.Listen("tcp"":50051")
    if err != nil {
        // 處理監聽失敗的錯誤
    }

    server := grpc.NewServer()
    RegisterGreeterServer(server, &Greeter{})

    // 在gRPC服務上啓用反射服務
    reflection.Register(server)

    go func() {
        if err := server.Serve(listener); err != nil {
            // 處理gRPC服務啓動錯誤
        }
    }()

    // 等待中斷信號來優雅地關閉gRPC服務器
    stop := make(chan os.Signal, 1)
    signal.Notify(stop, os.Interrupt)

    <-stop // 等待中斷信號
    fmt.Println("Shutting down gRPC server...")

    server.GracefulStop()
    fmt.Println("gRPC server gracefully stopped")
}

3. Worker 協程平滑關閉

對於 worker 協程的平滑關閉,可以使用 context.Context 實現。

package main

import (
    "context"
    "fmt"
    "os"
    "os/signal"
    "sync"
    "time"
)

func worker(ctx context.Context, wg *sync.WaitGroup) {
    defer wg.Done()

    for {
        select {
        case <-ctx.Done():
            fmt.Println("Worker received shutdown signal")
            return
        default:
            // 執行工作任務
            fmt.Println("Working...")
            time.Sleep(time.Second)
        }
    }
}

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    var wg sync.WaitGroup

    // 啓動worker協程
    wg.Add(1)
    go worker(ctx, &wg)

    // 等待中斷信號來優雅地關閉worker協程
    stop := make(chan os.Signal, 1)
    signal.Notify(stop, os.Interrupt)

    <-stop // 等待中斷信號
    fmt.Println("Shutting down...")

    // 發送關閉信號給worker協程
    cancel()
    wg.Wait()
    fmt.Println("Shutdown complete")
}

4. 實現 io.Closer 接口的自定義服務平滑關閉

實現 io.Closer 接口的服務可以通過調用 Close 方法進行平滑關閉。

package main

import (
    "fmt"
    "os"
    "os/signal"
    "sync"
    "time"
)

type MyService struct {
    mu sync.Mutex
    // 其他服務相關的字段
}

func (s *MyService) Close() error {
    s.mu.Lock()
    defer s.mu.Unlock()

    // 執行關閉服務的操作
    fmt.Println("Closing MyService...")
    return nil
}

func main() {
    service := &MyService{}

    // 等待中斷信號來優雅地關閉服務
    stop := make(chan os.Signal, 1)
    signal.Notify(stop, os.Interrupt)

    <-stop // 等待中斷信號
    fmt.Println("Shutting down...")

    // 調用Close方法進行平滑關閉
    if closer, ok := service.(interface{ Close() error }); ok {
        if err := closer.Close(); err != nil {
            fmt.Println("Error closing service:", err)
        }
    }
    fmt.Println("Shutdown complete")
}

以上是一些 Golang 中實現程序優雅退出的方法,具體的實現方式取決於你的應用程序結構和使用的庫。

在實際應用中,你可能需要組合使用這些方法以確保整個應用程序在退出時都能夠平滑關閉。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/NDXVDNQPvw_ALzSR2eTn2w