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

詳解Golang如何優(yōu)雅的終止一個(gè)服務(wù)

 更新時(shí)間:2022年03月21日 12:57:44   作者:磊磊落落愛(ài)分享  
后端服務(wù)通常會(huì)需要?jiǎng)?chuàng)建子協(xié)程來(lái)進(jìn)行相應(yīng)的作業(yè),但進(jìn)程接受到終止信號(hào)或正常結(jié)束時(shí),并沒(méi)有判斷或等待子協(xié)程執(zhí)行結(jié)束,下面這篇文章主要給大家介紹了關(guān)于Golang如何優(yōu)雅的終止一個(gè)服務(wù)的相關(guān)資料,需要的朋友可以參考下

前言

采用常規(guī)方式啟動(dòng)一個(gè) Golang http 服務(wù)時(shí),若服務(wù)被意外終止或中斷,即未等待服務(wù)對(duì)現(xiàn)有請(qǐng)求連接處理并正常返回且亦未對(duì)服務(wù)停止前作一些必要的處理工作,這樣即會(huì)造成服務(wù)硬終止。這種方式不是很優(yōu)雅。

參看如下代碼,該 http 服務(wù)請(qǐng)求路徑為根路徑,請(qǐng)求該路徑,其會(huì)在 2s 后返回 hello。

var addr = flag.String("server addr", ":8080", "server address")

func main() {
? ? http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
? ? ? ? time.Sleep(2 * time.Second)
? ? ? ? fmt.Fprintln(w, "hello")
? ? })
? ? http.ListenAndServe(*addr, nil)
}

若服務(wù)啟動(dòng)后,請(qǐng)求http://localhost:8080/,然后使用 Ctrl+C 立即中斷服務(wù),服務(wù)即會(huì)立即退出(exit status 2),請(qǐng)求未正常返回(ERR_CONNECTION_REFUSED),連接即馬上斷了。

接下來(lái)介紹使用 http.Server 的 Shutdown 方法結(jié)合 signal.Notify 來(lái)優(yōu)雅的終止服務(wù)。

1 Shutdown 方法

Golang http.Server 結(jié)構(gòu)體有一個(gè)終止服務(wù)的方法 Shutdown,其 go doc 如下。

func (srv *Server) Shutdown(ctx context.Context) error
    Shutdown gracefully shuts down the server without interrupting any active
    connections. Shutdown works by first closing all open listeners, then
    closing all idle connections, and then waiting indefinitely for connections
    to return to idle and then shut down. If the provided context expires before
    the shutdown is complete, Shutdown returns the context's error, otherwise it
    returns any error returned from closing the Server's underlying Listener(s).

    When Shutdown is called, Serve, ListenAndServe, and ListenAndServeTLS
    immediately return ErrServerClosed. Make sure the program doesn't exit and
    waits instead for Shutdown to return.

    Shutdown does not attempt to close nor wait for hijacked connections such as
    WebSockets. The caller of Shutdown should separately notify such long-lived
    connections of shutdown and wait for them to close, if desired. See
    RegisterOnShutdown for a way to register shutdown notification functions.

    Once Shutdown has been called on a server, it may not be reused; future
    calls to methods such as Serve will return ErrServerClosed.

由文檔可知:

使用 Shutdown 可以?xún)?yōu)雅的終止服務(wù),其不會(huì)中斷活躍連接。

其工作過(guò)程為:首先關(guān)閉所有開(kāi)啟的監(jiān)聽(tīng)器,然后關(guān)閉所有閑置連接,最后等待活躍的連接均閑置了才終止服務(wù)。

若傳入的 context 在服務(wù)完成終止前已超時(shí),則 Shutdown 方法返回 context 的錯(cuò)誤,否則返回任何由關(guān)閉服務(wù)監(jiān)聽(tīng)器所引起的錯(cuò)誤。

當(dāng) Shutdown 方法被調(diào)用時(shí),Serve、ListenAndServe 及 ListenAndServeTLS 方法會(huì)立刻返回 ErrServerClosed 錯(cuò)誤。請(qǐng)確保 Shutdown 未返回時(shí),勿退出程序。

對(duì)諸如 WebSocket 等的長(zhǎng)連接,Shutdown 不會(huì)嘗試關(guān)閉也不會(huì)等待這些連接。若需要,需調(diào)用者分開(kāi)額外處理(諸如通知諸長(zhǎng)連接或等待它們關(guān)閉,使用 RegisterOnShutdown 注冊(cè)終止通知函數(shù))。

一旦對(duì) server 調(diào)用了 Shutdown,其即不可再使用了(會(huì)報(bào) ErrServerClosed 錯(cuò)誤)。

有了 Shutdown 方法,我們知道在服務(wù)終止前,調(diào)用該方法即可等待活躍連接正常返回,然后優(yōu)雅的關(guān)閉。

但服務(wù)啟動(dòng)后的某一時(shí)刻,程序如何知道服務(wù)被中斷了呢?服務(wù)被中斷時(shí)如何通知程序,然后調(diào)用 Shutdown 作處理呢?接下來(lái)看一下系統(tǒng)信號(hào)通知函數(shù)的作用。

2 signal.Notify 函數(shù)

signal 包的 Notify 函數(shù)提供系統(tǒng)信號(hào)通知的能力,其 go doc 如下。

func Notify(c chan<- os.Signal, sig ...os.Signal)
    Notify causes package signal to relay incoming signals to c. If no signals
    are provided, all incoming signals will be relayed to c. Otherwise, just the
    provided signals will.

    Package signal will not block sending to c: the caller must ensure that c
    has sufficient buffer space to keep up with the expected signal rate. For a
    channel used for notification of just one signal value, a buffer of size 1
    is sufficient.

    It is allowed to call Notify multiple times with the same channel: each call
    expands the set of signals sent to that channel. The only way to remove
    signals from the set is to call Stop.

    It is allowed to call Notify multiple times with different channels and the
    same signals: each channel receives copies of incoming signals
    independently.

由文檔可知:

參數(shù) c 是調(diào)用者的信號(hào)接收通道,Notify 可將進(jìn)入的信號(hào)轉(zhuǎn)到 c。sig 參數(shù)為需要轉(zhuǎn)發(fā)的信號(hào)類(lèi)型,若不指定,所有進(jìn)入的信號(hào)都將會(huì)轉(zhuǎn)到 c。

信號(hào)不會(huì)阻塞式的發(fā)給 c:調(diào)用者需確保 c 有足夠的緩沖空間,以應(yīng)對(duì)指定信號(hào)的高頻發(fā)送。對(duì)于用于通知僅一個(gè)信號(hào)值的通道,緩沖大小為 1 即可。

同一個(gè)通道可以調(diào)用 Notify 多次:每個(gè)調(diào)用擴(kuò)展了發(fā)送至該通道的信號(hào)集合。僅可調(diào)用 Stop 來(lái)從信號(hào)集合移除信號(hào)。

允許不同的通道使用同樣的信號(hào)參數(shù)調(diào)用 Notify 多次:每個(gè)通道獨(dú)立的接收進(jìn)入信號(hào)的副本。

綜上,有了 signal.Notify,傳入一個(gè) chan 并指定中斷參數(shù),這樣當(dāng)系統(tǒng)中斷時(shí),即可接收到信號(hào)。

參看如下代碼,當(dāng)使用 Ctrl+C 時(shí),c 會(huì)接收到中斷信號(hào),程序會(huì)在打印“program interrupted”語(yǔ)句后退出。

func main() {
? ? c := make(chan os.Signal)
? ? signal.Notify(c, os.Interrupt)
? ? <-c
? ? log.Fatal("program interrupted")
}
$ go run main.go

Ctrl+C

2019/06/11 17:59:11 program interrupted
exit status 1

3 Server 優(yōu)雅的終止

接下來(lái)我們使用如上 signal.Notify 結(jié)合 http.Server 的 Shutdown 方法實(shí)現(xiàn)服務(wù)優(yōu)雅的終止。

如下代碼,Handler 與文章開(kāi)始時(shí)的處理邏輯一樣,其會(huì)在2s后返回 hello。

創(chuàng)建一個(gè) http.Server 實(shí)例,指定端口與 Handler。

聲明一個(gè) processed chan,其用來(lái)保證服務(wù)優(yōu)雅的終止后再退出主 goroutine。

新啟一個(gè) goroutine,其會(huì)監(jiān)聽(tīng) os.Interrupt 信號(hào),一旦服務(wù)被中斷即調(diào)用服務(wù)的 Shutdown 方法,確保活躍連接的正常返回(本代碼使用的 Context 超時(shí)時(shí)間為 3s,大于服務(wù) Handler 的處理時(shí)間,所以不會(huì)超時(shí))。

處理完成后,關(guān)閉 processed 通道,最后主 goroutine 退出。

代碼同時(shí)托管在 GitHub,歡迎關(guān)注(github.com/olzhy/go-excercises)。

var addr = flag.String("server addr", ":8080", "server address")

func main() {
? ? // handler
? ? handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
? ? ? ? time.Sleep(2 * time.Second)
? ? ? ? fmt.Fprintln(w, "hello")
? ? })

? ? // server
? ? srv := http.Server{
? ? ? ? Addr: ? ?*addr,
? ? ? ? Handler: handler,
? ? }

? ? // make sure idle connections returned
? ? processed := make(chan struct{})
? ? go func() {
? ? ? ? c := make(chan os.Signal, 1)
? ? ? ? signal.Notify(c, os.Interrupt)
? ? ? ? <-c

? ? ? ? ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
? ? ? ? defer cancel()
? ? ? ? if err := srv.Shutdown(ctx); nil != err {
? ? ? ? ? ? log.Fatalf("server shutdown failed, err: %v\n", err)
? ? ? ? }
? ? ? ? log.Println("server gracefully shutdown")

? ? ? ? close(processed)
? ? }()

? ? // serve
? ? err := srv.ListenAndServe()
? ? if http.ErrServerClosed != err {
? ? ? ? log.Fatalf("server not gracefully shutdown, err :%v\n", err)
? ? }

? ? // waiting for goroutine above processed
? ? <-processed
}

總結(jié)

到此這篇關(guān)于Golang如何優(yōu)雅的終止一個(gè)服務(wù)的文章就介紹到這了,更多相關(guān)Golang終止服務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go?GORM?事務(wù)詳細(xì)介紹

    Go?GORM?事務(wù)詳細(xì)介紹

    這篇文章主要介紹了Go?GORM事務(wù)詳細(xì)介紹,GORM?會(huì)在事務(wù)里執(zhí)行寫(xiě)入操作創(chuàng)建、更新、刪除,具體詳細(xì)介紹需要的朋友可以參考下面文章的簡(jiǎn)單介紹
    2022-07-07
  • Go?語(yǔ)言的?:=的具體使用

    Go?語(yǔ)言的?:=的具體使用

    本文主要介紹了Go?語(yǔ)言的?:=的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • golang 流式讀取和發(fā)送使用場(chǎng)景示例

    golang 流式讀取和發(fā)送使用場(chǎng)景示例

    這篇文章主要為大家介紹了golang 流式讀取和發(fā)送使用場(chǎng)景示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 淺析Go匯編語(yǔ)法和MatrixOne使用介紹

    淺析Go匯編語(yǔ)法和MatrixOne使用介紹

    MatrixOne由Go語(yǔ)言所開(kāi)發(fā)是一個(gè)新一代超融合異構(gòu)數(shù)據(jù)庫(kù),致力于打造單一架構(gòu)處理TP、AP、流計(jì)算等多種負(fù)載的極簡(jiǎn)大數(shù)據(jù)引擎,今天通過(guò)本文給大家介紹Go匯編語(yǔ)法和MatrixOne使用,感興趣的朋友一起看看吧
    2022-04-04
  • GoLang?channel底層代碼分析詳解

    GoLang?channel底層代碼分析詳解

    Channel和goroutine的結(jié)合是Go并發(fā)編程的大殺器。而Channel的實(shí)際應(yīng)用也經(jīng)常讓人眼前一亮,通過(guò)與select,cancel,timer等結(jié)合,它能實(shí)現(xiàn)各種各樣的功能。接下來(lái),我們就要梳理一下GoLang?channel底層代碼實(shí)現(xiàn)
    2022-10-10
  • 帶你在Go?test中體驗(yàn)jest的安裝使用

    帶你在Go?test中體驗(yàn)jest的安裝使用

    這篇文章帶你在Go?test中體驗(yàn)jest的安裝使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 一文了解Go語(yǔ)言中編碼規(guī)范的使用

    一文了解Go語(yǔ)言中編碼規(guī)范的使用

    這篇文章主要介紹了一文了解Go語(yǔ)言中編碼規(guī)范的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • Go操作etcd的實(shí)現(xiàn)示例

    Go操作etcd的實(shí)現(xiàn)示例

    etcd是近幾年比較火熱的一個(gè)開(kāi)源的、分布式的鍵值對(duì)數(shù)據(jù)存儲(chǔ)系統(tǒng),提供共享配置、服務(wù)的注冊(cè)和發(fā)現(xiàn),本文主要介紹etcd的安裝和使用,感興趣的可以了解一下
    2021-09-09
  • Go?語(yǔ)言?json解析框架與?gjson?詳解

    Go?語(yǔ)言?json解析框架與?gjson?詳解

    這篇文章主要介紹了Go語(yǔ)言json解析框架與gjson,JSON?解析是我們不可避免的常見(jiàn)問(wèn)題,在Go語(yǔ)言中,我們可以借助gjson庫(kù)來(lái)方便的進(jìn)行json屬性的提取與解析,需要的朋友可以參考一下
    2022-07-07
  • 詳解Go程序添加遠(yuǎn)程調(diào)用tcpdump功能

    詳解Go程序添加遠(yuǎn)程調(diào)用tcpdump功能

    這篇文章主要介紹了go程序添加遠(yuǎn)程調(diào)用tcpdump功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05

最新評(píng)論

乌审旗| 武宣县| 云霄县| 宽城| 新民市| 锡林浩特市| 宜昌市| 宁远县| 开平市| 田东县| 新安县| 准格尔旗| 西和县| 崇左市| 抚远县| 甘肃省| 凤凰县| 黎川县| 香河县| 三原县| 南城县| 喀什市| 醴陵市| 屏东市| 卫辉市| 蛟河市| 长寿区| 当涂县| 治多县| 仙桃市| 佛教| 沂水县| 盈江县| 余干县| 伊宁县| 南城县| 双流县| 南投市| 苏尼特右旗| 梁平县| 娄烦县|