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

go如何優(yōu)雅關(guān)閉Graceful?Shutdown服務(wù)

 更新時(shí)間:2023年05月15日 08:55:12   作者:cainmusic  
這篇文章主要為大家介紹了go優(yōu)雅關(guān)閉Graceful?Shutdown服務(wù)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

Shutdown方法

Go1.8之后有了Shutdown方法,用來優(yōu)雅的關(guān)閉(Graceful Shutdown)服務(wù)。

func (srv *Server) Shutdown(ctx context.Context) error

這個(gè)方法會(huì)在調(diào)用時(shí)進(jìn)行下述操作:

1.關(guān)閉所有open listeners

2.關(guān)閉所有idle connections

3.無限期等待connections回歸idle狀態(tài)

4.之后關(guān)閉服務(wù)

注:3的無限期等待可以用context的超時(shí)來解決。

RegisterOnShutdown方法

Go1.9之后有了RegisterOnShutdown方法,用來在優(yōu)雅的關(guān)閉服務(wù)的同時(shí)處理一些退出任務(wù)。

func (srv *Server) RegisterOnShutdown(f func())

關(guān)于RegisterOnShutdown如何生效,我們看代碼。

type Server struct {
    ...
    onShutdown []func()
}

func (srv *Server) RegisterOnShutdown(f func()) {
    srv.mu.Lock()
    srv.onShutdown = append(srv.onShutdown, f)
    srv.mu.Unlock()
}

func (srv *Server) Shutdown(ctx context.Context) error {
    ...

    srv.mu.Lock()
    ...
    for _, f := range srv.onShutdown {
        go f()
    }
    srv.mu.Unlock()

    ...
}

由代碼可知,在通過RegisterOnShutdown進(jìn)行注冊(cè)之后,這些函數(shù)被放入一個(gè)函數(shù)切片中,并在Shutdown被調(diào)用的時(shí)候,為每個(gè)函數(shù)啟動(dòng)了一個(gè)goroutine進(jìn)行處理。

但由于沒有進(jìn)行后續(xù)處理,于是這里有個(gè)小問題,Shutdown是不等待這些處理函數(shù)結(jié)束的,就可能比這些處理函數(shù)先完成并進(jìn)而結(jié)束程序。

package main
import (
    "context"
    "log"
    "net/http"
    "os"
    "os/signal"
    "time"
)
func main() {
    var srv http.Server
    srv.RegisterOnShutdown(func() {
        time.Sleep(3 * time.Second)
        log.Println("Exit func")
    })
    idleConnsClosed := make(chan struct{})
    go func() {
        sigint := make(chan os.Signal, 1)
        signal.Notify(sigint, os.Interrupt)
        <-sigint
        // We received an interrupt signal, shut down.
        if err := srv.Shutdown(context.Background()); err != nil {
            // Error from closing listeners, or context timeout:
            log.Printf("HTTP server Shutdown: %v", err)
        }
        close(idleConnsClosed)
    }()
    if err := srv.ListenAndServe(); err != http.ErrServerClosed {
        // Error starting or closing listener:
        log.Fatalf("HTTP server ListenAndServe: %v", err)
    }
    <-idleConnsClosed
}

運(yùn)行時(shí)Ctrl+c之后,服務(wù)立刻結(jié)束了,并未等待log.Println("Exit func")的輸出。

sync.WaitGroup處理退出函數(shù)

為了解決這個(gè)問題我們使用sync.WaitGroup來處理這些退出函數(shù),于是我們有了下面的代碼(解耦并增加了一些日志):

package main
import (
    "context"
    "log"
    "net/http"
    "os"
    "os/signal"
    "sync"
    "time"
)
func main() {
    var srv http.Server
    var wg sync.WaitGroup
    register := func(f func()) {
        wg.Add(1)
        log.Println("Exit func register")
        srv.RegisterOnShutdown(func() {
            defer wg.Done()
            f()
            log.Println("Exit func done")
        })
    }
    register(func() {
        time.Sleep(3 * time.Second)
        log.Println("Called on Shutdown")
    })
    idleConnsClosed := make(chan struct{})
    go func() {
        sigint := make(chan os.Signal, 1)
        signal.Notify(sigint, os.Interrupt)
        <-sigint
        // We received an interrupt signal, shut down.
        log.Println("Shutdown start")
        if err := srv.Shutdown(context.Background()); err != nil {
            // Error from closing listeners, or context timeout:
            log.Printf("HTTP server Shutdown: %v", err)
        }
        close(idleConnsClosed)
    }()
    if err := srv.ListenAndServe(); err != http.ErrServerClosed {
        // Error starting or closing listener:
        log.Fatalf("HTTP server ListenAndServe: %v", err)
    }
    <-idleConnsClosed
    log.Println("Shutdown finish")
    wg.Wait()
}

我們?cè)赗egisterOnShutdown時(shí)使用了time.Sleep(3 * time.Second)來模擬一個(gè)長(zhǎng)時(shí)間的退出程序,并且在"Shutdown finish"之后進(jìn)行等待,等待退出程序完成任務(wù)。

執(zhí)行日志如下:

2023/05/12 16:48:53 Exit func register
^C2023/05/12 16:48:54 Shutdown start
2023/05/12 16:48:54 Shutdown finish
2023/05/12 16:48:57 Called on Shutdown
2023/05/12 16:48:57 Exit func done

可以看到這個(gè)服務(wù)本身很輕,Shutdown start之后立刻就finish并來到wg.Wait(),并等待register的函數(shù)完成之后再退出程序。

另外,如果在服務(wù)運(yùn)行的過程中需要啟動(dòng)一些其他的任務(wù),也可以使用

wg.Add(1)
go func() {
    defer wg.Done()
    ...
}

來保證任務(wù)在服務(wù)Shutdown之后可以順利完成。

以上就是go如何優(yōu)雅關(guān)閉Graceful Shutdown服務(wù)的詳細(xì)內(nèi)容,更多關(guān)于go關(guān)閉Graceful Shutdown的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Golang回調(diào)函數(shù)與閉包和接口函數(shù)的定義及使用介紹

    Golang回調(diào)函數(shù)與閉包和接口函數(shù)的定義及使用介紹

    這篇文章主要介紹了Golang回調(diào)函數(shù)與閉包和接口函數(shù)的定義及使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-05-05
  • Golang常見錯(cuò)誤之值拷貝和for循環(huán)中的單一變量詳解

    Golang常見錯(cuò)誤之值拷貝和for循環(huán)中的單一變量詳解

    這篇文章主要給大家介紹了關(guān)于Golang常見錯(cuò)誤之值拷貝和for循環(huán)中單一變量的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11
  • GO 切片刪除元素的三種方法

    GO 切片刪除元素的三種方法

    本文主要介紹了GO 切片刪除元素,根據(jù)要?jiǎng)h除元素的位置有三種情況,分別是從開頭位置刪除、從中間位置刪除和從尾部刪除,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-08-08
  • 破解IDEA(Goland)注冊(cè)碼設(shè)置 license server一直有效不過期的過程詳解

    破解IDEA(Goland)注冊(cè)碼設(shè)置 license server一直有效不過期的過程詳解

    這篇文章主要介紹了破解IDEA(Goland)注冊(cè)碼設(shè)置 license server一直有效不過期,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • PHP結(jié)構(gòu)型模式之組合模式

    PHP結(jié)構(gòu)型模式之組合模式

    這篇文章主要介紹了PHP組合模式Composite Pattern優(yōu)點(diǎn)與實(shí)現(xiàn),組合模式是一種結(jié)構(gòu)型模式,它允許你將對(duì)象組合成樹形結(jié)構(gòu)來表示“部分-整體”的層次關(guān)系。組合能讓客戶端以一致的方式處理個(gè)別對(duì)象和對(duì)象組合
    2023-04-04
  • Golang 文件操作:刪除指定的文件方式

    Golang 文件操作:刪除指定的文件方式

    這篇文章主要介紹了Golang 文件操作:刪除指定的文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • 一文詳解Golang的模塊版本管理與語義版本控制

    一文詳解Golang的模塊版本管理與語義版本控制

    在Golang中,模塊(module)是Go 1.11版本引入的依賴管理系統(tǒng),幫助開發(fā)者管理項(xiàng)目的依賴,在Go模塊推出之前,開發(fā)者通常使用GOPATH和vendor目錄來管理項(xiàng)目的依賴,本文將給大家詳細(xì)介紹Golang的模塊版本管理與語義版本控制,需要的朋友可以參考下
    2023-12-12
  • golang使用go test輸出單元測(cè)試覆蓋率的方式

    golang使用go test輸出單元測(cè)試覆蓋率的方式

    單元測(cè)試覆蓋率是衡量代碼質(zhì)量的一個(gè)重要指標(biāo),重要的代碼文件覆蓋率應(yīng)該至少達(dá)到80%以上,Java 可以通過JaCoCo 統(tǒng)計(jì)覆蓋率,那么go 項(xiàng)目如何進(jìn)行代碼覆蓋率測(cè)試呢,本文將給大家詳細(xì)的介紹一下golang使用go test輸出單元測(cè)試覆蓋率的方式,需要的朋友可以參考下
    2024-02-02
  • Golang字符串類型原理及其使用方法

    Golang字符串類型原理及其使用方法

    本文主要介紹了Golang字符串類型原理及其使用方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-09-09
  • go語言執(zhí)行等待直到后臺(tái)goroutine執(zhí)行完成實(shí)例分析

    go語言執(zhí)行等待直到后臺(tái)goroutine執(zhí)行完成實(shí)例分析

    這篇文章主要介紹了go語言執(zhí)行等待直到后臺(tái)goroutine執(zhí)行完成的方法,實(shí)例分析了Go語言中WaitGroup的使用技巧,需要的朋友可以參考下
    2015-03-03

最新評(píng)論

新津县| 平昌县| 长岛县| 尼玛县| 喀喇沁旗| 赫章县| 阿克陶县| 隆化县| 高阳县| 内乡县| 高唐县| 金平| 慈溪市| 仪陇县| 汶川县| 张掖市| 项城市| 莲花县| 峨眉山市| 宜兰县| 英德市| 易门县| 黔江区| 介休市| 潢川县| 惠安县| 尼勒克县| 施甸县| 台州市| 安顺市| 大名县| 兴化市| 新兴县| 成安县| 额尔古纳市| 廉江市| 景东| 尚志市| 郑州市| 梨树县| 富阳市|