最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang實(shí)現(xiàn)程序優(yōu)雅退出的方法詳解

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

1. 背景

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

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

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

如下我們以 http 服務(wù),gRPC 服務(wù),單獨(dú)的 woker 協(xié)程為例子,一步步說(shuō)明平滑關(guān)閉的寫法。

2. 常見的幾種平滑關(guān)閉

為了解決退出可能出現(xiàn)的潛在問題,平滑關(guān)閉一般做如下一些事情

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

2.1 http server 平滑關(guān)閉

原來(lái)的寫法

// 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())
    }
} 

帶平滑關(guān)閉的寫法

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

把平滑關(guān)閉注冊(cè)到http.Server的關(guān)閉函數(shù)中

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

2.2 gRPC server 平滑關(guān)閉

原來(lái)的寫法

// 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()
    // ...
}

帶平滑關(guān)閉的寫法 

// 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注冊(cè)到退出事件中
    quit.GetQuitEvent().RegisterStopFunc(grpcServer.GracefulStop)
    quit.WaitSignal()
}  

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

單獨(dú)的協(xié)程啟停,可以通過(guò)計(jì)數(shù)的方式注冊(cè)到退出事件處理器中。

1.啟動(dòng)協(xié)程 增加計(jì)數(shù)

quit.GetQuitEvent().AddGoroutine()

2.停止協(xié)程 減計(jì)數(shù) 

quit.GetQuitEvent().DoneGoroutine()

3.常駐后臺(tái)運(yùn)行的協(xié)程退出的條件改成退出事件是否結(jié)束的條件 

!quit.GetQuitEvent().HasFired()

4.常駐后臺(tái)運(yùn)行的協(xié)程若通過(guò) select 處理 chan,同時(shí)增加退出事件的chan

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

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

2.4 實(shí)現(xiàn) io.Closer 接口的自定義服務(wù)平滑關(guān)閉

實(shí)現(xiàn) io.Closer 接口的結(jié)構(gòu)體,增加到退出事件處理器中 

// startMyService start my service
func startMyService() {
    srv := NewMyService()
    // 注冊(cè)平滑關(guān)閉,退出時(shí)會(huì)調(diào)用 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 集成其他框架怎么做

退出信號(hào)處理由某一框架接管,尋找框架如何注冊(cè)退出函數(shù),優(yōu)秀的框架一般都會(huì)實(shí)現(xiàn)安全實(shí)現(xiàn)退出的機(jī)制。

如下將退出事件注冊(cè)到某一框架的平滑關(guān)閉函數(shù)中

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

以上就是Golang實(shí)現(xiàn)程序優(yōu)雅退出的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Golang程序退出的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go每日一庫(kù)之zap日志庫(kù)的安裝使用指南

    Go每日一庫(kù)之zap日志庫(kù)的安裝使用指南

    這篇文章主要為大家介紹了Go每日一庫(kù)之zap安裝使用示例學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • Golang實(shí)現(xiàn)web文件共享服務(wù)的示例代碼

    Golang實(shí)現(xiàn)web文件共享服務(wù)的示例代碼

    這篇文章主要介紹了Golang實(shí)現(xiàn)web文件共享服務(wù)的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-10-10
  • golang 打印error的堆棧信息操作

    golang 打印error的堆棧信息操作

    這篇文章主要介紹了golang 打印error的堆棧信息操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-05-05
  • 使用Go語(yǔ)言編寫一個(gè)簡(jiǎn)單的Web框架

    使用Go語(yǔ)言編寫一個(gè)簡(jiǎn)單的Web框架

    Go語(yǔ)言(又稱Golang)因其高效的性能和簡(jiǎn)潔的語(yǔ)法,在編寫Web框架方面表現(xiàn)出色,下面將詳細(xì)介紹如何使用Go語(yǔ)言編寫一個(gè)簡(jiǎn)單的Web框架,文中有詳細(xì)的代碼供大家參考,需要的朋友可以參考下
    2024-05-05
  • 一文帶你搞懂Golang結(jié)構(gòu)體內(nèi)存布局

    一文帶你搞懂Golang結(jié)構(gòu)體內(nèi)存布局

    結(jié)構(gòu)體在Go語(yǔ)言中是一個(gè)很重要的部分,在項(xiàng)目中會(huì)經(jīng)常用到。這篇文章主要帶大家看一下結(jié)構(gòu)體在內(nèi)存中是怎么分布的?通過(guò)對(duì)內(nèi)存布局的了解,可以幫助我們寫出更優(yōu)質(zhì)的代碼。感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助
    2022-10-10
  • golang使用sync.singleflight解決熱點(diǎn)緩存穿透問題

    golang使用sync.singleflight解決熱點(diǎn)緩存穿透問題

    在go的sync包中,有一個(gè)singleflight包,里面有一個(gè)?singleflight.go文件,代碼加注釋,一共200行出頭,通過(guò)?singleflight可以很容易實(shí)現(xiàn)緩存和去重的效果,避免重復(fù)計(jì)算,接下來(lái)我們就給大家詳細(xì)介紹一下sync.singleflight如何解決熱點(diǎn)緩存穿透問題
    2023-07-07
  • go語(yǔ)言搬磚之go jmespath實(shí)現(xiàn)查詢json數(shù)據(jù)

    go語(yǔ)言搬磚之go jmespath實(shí)現(xiàn)查詢json數(shù)據(jù)

    這篇文章主要為大家介紹了go語(yǔ)言搬磚之go jmespath實(shí)現(xiàn)查詢json數(shù)據(jù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 詳解如何在Golang中執(zhí)行shell命令

    詳解如何在Golang中執(zhí)行shell命令

    這篇文章主要為大家詳細(xì)介紹了在 golang 中執(zhí)行 shell 命令的多種方法和場(chǎng)景,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-02-02
  • Go語(yǔ)言學(xué)習(xí)之goroutine詳解

    Go語(yǔ)言學(xué)習(xí)之goroutine詳解

    Goroutine是建立在線程之上的輕量級(jí)的抽象。它允許我們以非常低的代價(jià)在同一個(gè)地址空間中并行地執(zhí)行多個(gè)函數(shù)或者方法,這篇文章主要介紹了Go語(yǔ)言學(xué)習(xí)之goroutine的相關(guān)知識(shí),需要的朋友可以參考下
    2020-02-02
  • GoLang讀取文件的10種方法實(shí)例

    GoLang讀取文件的10種方法實(shí)例

    讀取文件是所有編程語(yǔ)言中最常見的操作之一,下面這篇文章主要給大家介紹了關(guān)于GoLang讀取文件的10種方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06

最新評(píng)論

新民市| 乌拉特后旗| 蒙自县| 乌鲁木齐县| 西吉县| 漠河县| 昌乐县| 南涧| 敖汉旗| 宽城| 和静县| 康定县| 清涧县| 南投市| 大田县| 清流县| 博白县| 石屏县| 屏东市| 启东市| 博罗县| 固原市| 比如县| 拜城县| 镶黄旗| 瓦房店市| 永兴县| 资阳市| 伊宁市| 平武县| 赤水市| 河源市| 丰镇市| 曲松县| 上饶市| 阜平县| 怀化市| 永吉县| 察雅县| 鸡西市| 石屏县|