欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang實現程序優(yōu)雅退出的方法詳解

 更新時間:2022年06月15日 15:40:05   作者:Mr.YF  
項目開發(fā)過程中,隨著需求的迭代,代碼的發(fā)布會頻繁進行,在發(fā)布過程中,Golang如何讓程序做到優(yōu)雅的退出?本文就來詳細為大家講講

1. 背景

項目開發(fā)過程中,隨著需求的迭代,代碼的發(fā)布會頻繁進行,在發(fā)布過程中,如何讓程序做到優(yōu)雅的退出?

為什么需要優(yōu)雅的退出?

  • 你的 http 服務,監(jiān)聽端口沒有關閉,客戶的請求發(fā)過來了,但處理了一半,可能造成臟數據。
  • 你的協(xié)程 worker 的一個任務運行了一半,程序退出了,結果不符合預期。

如下我們以 http 服務,gRPC 服務,單獨的 woker 協(xié)程為例子,一步步說明平滑關閉的寫法。

2. 常見的幾種平滑關閉

為了解決退出可能出現的潛在問題,平滑關閉一般做如下一些事情

  • 關閉對外的監(jiān)聽端口,拒絕新的連接
  • 關閉異步運行的協(xié)程
  • 關閉依賴的資源
  • 等待如上資源關閉
  • 然后平滑關閉

2.1 http server 平滑關閉

原來的寫法

// startHttpServer start http server
func startHttpServer() {
    mux := http.NewServeMux()
    // mux.Handle("/metrics", promhttp.Handler())
    if err := http.ListenAndServe(":1608", mux); err != nil {
        log.Fatal("startHttpServer ListenAndServe error: " + err.Error())
    }
} 

帶平滑關閉的寫法

// startHttpServer start http server
func startHttpServer() {
    mux := http.NewServeMux()
    // mux.Handle("/metrics", promhttp.Handler())
    srv := &http.Server{
        Addr:    ":1608",
        Handler: mux,
    }
    // 注冊平滑關閉,退出時會調用 srv.Shutdown(ctx)
    quit.GetQuitEvent().RegisterQuitCloser(srv)
    if err := srv.ListenAndServe(); err != nil {
        log.Fatal("startHttpServer ListenAndServe error: " + err.Error())
    }
}

把平滑關閉注冊到http.Server的關閉函數中

// startHttpServer start http server
func startHttpServer() {
    mux := http.NewServeMux()
    // mux.Handle("/metrics", promhttp.Handler())
    srv := &http.Server{
        Addr:    ":1608",
        Handler: mux,
    }
    // 把平滑退出注冊到http.Server中
    srv.RegisterOnShutdown(quit.GetQuitEvent().GracefulStop)
    if err := srv.ListenAndServe(); err != nil {
        log.Fatal("startHttpServer ListenAndServe error: " + err.Error())
    }
}

2.2 gRPC server 平滑關閉

原來的寫法

// startGrpcServer start grpc server
func startGrpcServer() {
    listen, err := net.Listen("tcp", "0.0.0.0:9999")
    if err != nil {
        log.Fatalf("Failed to listen: %v", err)
        return
    }
    grpcServer := grpc.NewServer()
    // helloBoot.GrpcRegister(grpcServer)
    go grpcServer.Serve(listen)
    defer grpcServer.GracefulStop()
    // ...
}

帶平滑關閉的寫法 

// startGrpcServer start grpc server
func startGrpcServer() {
    listen, err := net.Listen("tcp", "0.0.0.0:9999")
    if err != nil {
        log.Fatalf("Failed to listen: %v", err)
        return
    }
    grpcServer := grpc.NewServer()
    // helloBoot.GrpcRegister(grpcServer)
    go grpcServer.Serve(listen)
    // 把 grpc 的GracefulStop注冊到退出事件中
    quit.GetQuitEvent().RegisterStopFunc(grpcServer.GracefulStop)
    quit.WaitSignal()
}  

2.3 worker 協(xié)程平滑關閉

單獨的協(xié)程啟停,可以通過計數的方式注冊到退出事件處理器中。

1.啟動協(xié)程 增加計數

quit.GetQuitEvent().AddGoroutine()

2.停止協(xié)程 減計數 

quit.GetQuitEvent().DoneGoroutine()

3.常駐后臺運行的協(xié)程退出的條件改成退出事件是否結束的條件 

!quit.GetQuitEvent().HasFired()

4.常駐后臺運行的協(xié)程若通過 select 處理 chan,同時增加退出事件的chan

case <-quit.GetQuitEvent().Done()

// myWorker my worker
type myWorker struct {
}
 
// RunWorkerWithChan run Goroutine worker
func (m *myWorker) RunWorkerWithChan() {
    // 啟動一個Goroutine時,增加Goroutine數
    quit.GetQuitEvent().AddGoroutine()
    defer func() {
        // 一個Goroutine退出時,減少Goroutine數
        quit.GetQuitEvent().DoneGoroutine()
    }()
    // 退出時,此次退出
    for !quit.GetQuitEvent().HasFired() {
        select {
        // 退出時,收到退出信號
        case <-quit.GetQuitEvent().Done():
            break
            //case msg := <- m.YouChan:
            // handle msg
        }
    }
}
 
// RunWorker run Goroutine worker
func (m *myWorker) RunWorker() {
    // 啟動一個Goroutine時,增加Goroutine數
    quit.GetQuitEvent().AddGoroutine()
    defer func() {
        // 一個Goroutine退出時,減少Goroutine數
        quit.GetQuitEvent().DoneGoroutine()
    }()
 
    // 退出時,此次退出
    for !quit.GetQuitEvent().HasFired() {
        // ...
    }
}

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

實現 io.Closer 接口的結構體,增加到退出事件處理器中 

// startMyService start my service
func startMyService() {
    srv := NewMyService()
    // 注冊平滑關閉,退出時會調用 srv.Close()
    quit.GetQuitEvent().RegisterCloser(srv)
    srv.Run()
}
 
// myService my service
type myService struct {
    isStop bool
}
 
// NewMyService new
func NewMyService() *myService {
    return &myService{}
}
 
// Close my service
func (m *myService) Close() error {
    m.isStop = true
    return nil
}
 
// Run my service
func (m *myService) Run() {
    for !m.isStop {
        // ....
    }
}

2.5 集成其他框架怎么做

退出信號處理由某一框架接管,尋找框架如何注冊退出函數,優(yōu)秀的框架一般都會實現安全實現退出的機制。

如下將退出事件注冊到某一框架的平滑關閉函數中

func startMyServer() {
    // ...
    // xxx框架退出函數注冊退出事件
    xxx.RegisterQuitter(func() {
        quit.GetQuitEvent().GracefulStop()
    })
}

以上就是Golang實現程序優(yōu)雅退出的方法詳解的詳細內容,更多關于Golang程序退出的資料請關注腳本之家其它相關文章!

相關文章

  • gomod包依賴管理工具使用詳解

    gomod包依賴管理工具使用詳解

    這篇文章主要為大家介紹了gomod如何解決包管理問題使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • Golang函數這些神操作你知道哪些

    Golang函數這些神操作你知道哪些

    這篇文章主要為大家介紹了一些Golang中函數的神操作,不知道你都知道哪些呢?文中的示例代碼講解詳細,具有一定的學習價值,需要的可以參考一下
    2023-02-02
  • Golang之defer 延遲調用操作

    Golang之defer 延遲調用操作

    這篇文章主要介紹了Golang之defer 延遲調用操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 使用golang實現在屏幕上打印進度條的操作

    使用golang實現在屏幕上打印進度條的操作

    這篇文章主要介紹了使用golang實現在屏幕上打印進度條的操作,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • Golang開發(fā)中如何解決共享變量問題

    Golang開發(fā)中如何解決共享變量問題

    Go提供了傳統(tǒng)通過共享變量,也就是共享內存的方式來實現并發(fā)。這篇文章會介紹 Go提供的相關機制,對Golang共享變量相關知識感興趣的朋友一起看看吧
    2021-09-09
  • 使用go求冪的幾種方法小結

    使用go求冪的幾種方法小結

    這篇文章主要介紹了使用go求冪的幾種方法小結,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • golang1.21泛型函數全面講解

    golang1.21泛型函數全面講解

    在Go編程語言中,泛型一直是一個備受期待的特性,隨著Go?1.21的發(fā)布,本文旨在提供Go?1.21中泛型的詳細探索,闡明它們的優(yōu)點、語法、實現和最佳實踐,希望對大家有所幫助
    2023-09-09
  • 深入理解Go語言設計模式之函數式選項模式

    深入理解Go語言設計模式之函數式選項模式

    在 Go 語言中,函數選項模式(Function Options Pattern)是一種常見且強大的設計模式,用于構建可擴展、易于使用和靈活的 API,本文就來看看它的具體用法吧
    2023-05-05
  • Go語言Gin框架前后端分離項目開發(fā)實例

    Go語言Gin框架前后端分離項目開發(fā)實例

    本文主要介紹了Go語言Gin框架前后端分離項目開發(fā)工程化實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-11-11
  • Go實現map轉json的示例詳解

    Go實現map轉json的示例詳解

    這篇文章主要為大家詳細介紹了如何利用Go語言實現map轉json的功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-09-09

最新評論