亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

前言

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

參看如下代碼,該 http 服務請求路徑為根路徑,請求該路徑,其會在 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)
}

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

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

1 Shutdown 方法

Golang http.Server 結構體有一個終止服務的方法 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 可以優(yōu)雅的終止服務,其不會中斷活躍連接。

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

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

當 Shutdown 方法被調用時,Serve、ListenAndServe 及 ListenAndServeTLS 方法會立刻返回 ErrServerClosed 錯誤。請確保 Shutdown 未返回時,勿退出程序。

對諸如 WebSocket 等的長連接,Shutdown 不會嘗試關閉也不會等待這些連接。若需要,需調用者分開額外處理(諸如通知諸長連接或等待它們關閉,使用 RegisterOnShutdown 注冊終止通知函數(shù))。

一旦對 server 調用了 Shutdown,其即不可再使用了(會報 ErrServerClosed 錯誤)。

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

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

2 signal.Notify 函數(shù)

signal 包的 Notify 函數(shù)提供系統(tǒng)信號通知的能力,其 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 是調用者的信號接收通道,Notify 可將進入的信號轉到 c。sig 參數(shù)為需要轉發(fā)的信號類型,若不指定,所有進入的信號都將會轉到 c。

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

同一個通道可以調用 Notify 多次:每個調用擴展了發(fā)送至該通道的信號集合。僅可調用 Stop 來從信號集合移除信號。

允許不同的通道使用同樣的信號參數(shù)調用 Notify 多次:每個通道獨立的接收進入信號的副本。

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

參看如下代碼,當使用 Ctrl+C 時,c 會接收到中斷信號,程序會在打印“program interrupted”語句后退出。

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)雅的終止

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

如下代碼,Handler 與文章開始時的處理邏輯一樣,其會在2s后返回 hello。

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

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

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

處理完成后,關閉 processed 通道,最后主 goroutine 退出。

代碼同時托管在 GitHub,歡迎關注(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
}

總結

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

相關文章

  • go程序測試CPU占用率統(tǒng)計ps?vs?top兩種不同方式對比

    go程序測試CPU占用率統(tǒng)計ps?vs?top兩種不同方式對比

    這篇文章主要為大家介紹了go程序測試CPU占用率統(tǒng)計ps?vs?top兩種不同方式對比,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • 淺析Go語言中的同步與異步處理

    淺析Go語言中的同步與異步處理

    在開發(fā)過程中,當需要同時處理多個操作時,開發(fā)者經常面臨同步和異步兩種處理方式的選擇,下面小編就來和大家詳細介紹一下Go語言中的同步與異步處理吧
    2023-11-11
  • 基于HLS創(chuàng)建Golang視頻流服務器的優(yōu)缺點

    基于HLS創(chuàng)建Golang視頻流服務器的優(yōu)缺點

    HLS 是 HTTP Live Streaming 的縮寫,是蘋果開發(fā)的一種基于 HTTP 的自適應比特率流媒體傳輸協(xié)議。這篇文章主要介紹了基于 HLS 創(chuàng)建 Golang 視頻流服務器,需要的朋友可以參考下
    2021-08-08
  • Go語言學習之操作MYSQL實現(xiàn)CRUD

    Go語言學習之操作MYSQL實現(xiàn)CRUD

    Go官方提供了database包,database包下有sql/driver。該包用來定義操作數(shù)據(jù)庫的接口,這保證了無論使用哪種數(shù)據(jù)庫,操作方式都是相同的。本文就來和大家聊聊Go語言如何操作MYSQL實現(xiàn)CRUD,希望對大家有所幫助
    2023-02-02
  • go并發(fā)實現(xiàn)素數(shù)篩的代碼

    go并發(fā)實現(xiàn)素數(shù)篩的代碼

    這篇文章主要介紹了go并發(fā)實現(xiàn)素數(shù)篩的代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • 淺析Go語言中的緩沖區(qū)及其在fmt包中的應用

    淺析Go語言中的緩沖區(qū)及其在fmt包中的應用

    這篇文章主要為大家詳細介紹了Go語言中的緩沖區(qū)及其在fmt包中的應用的相關知識,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2024-01-01
  • go語言中[]*int和*[]int的具體使用

    go語言中[]*int和*[]int的具體使用

    本文主要介紹了go語言中[]*int和*[]int的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-04-04
  • go xorm存庫處理null值問題

    go xorm存庫處理null值問題

    這篇文章主要介紹了go xorm存庫處理null值問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Go中時間與時區(qū)問題的深入講解

    Go中時間與時區(qū)問題的深入講解

    go語言中如果不設置指定的時區(qū),通過time.Now()獲取到的就是本地時區(qū),下面這篇文章主要給大家介紹了關于Go中時間與時區(qū)問題的相關資料,需要的朋友可以參考下
    2021-12-12
  • Golang字符串的拼接方法匯總

    Golang字符串的拼接方法匯總

    字符串拼接在日常開發(fā)中是很常見的需求,今天我們來探討下如何用golang來實現(xiàn)字符串的拼接
    2018-10-10

最新評論