中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

go關閉Graceful?Shutdown服務的幾種方法

發布時間:2023-07-03 14:14:02 來源:億速云 閱讀:142 作者:栢白 欄目:開發技術

本篇文章和大家了解一下go關閉Graceful Shutdown服務的幾種方法。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有所幫助。

目錄
  • Shutdown方法

  • RegisterOnShutdown方法

    • sync.WaitGroup處理退出函數

Shutdown方法

Go1.8之后有了Shutdown方法,用來優雅的關閉(Graceful Shutdown)服務。

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

這個方法會在調用時進行下述操作:

1.關閉所有open listeners

2.關閉所有idle connections

3.無限期等待connections回歸idle狀態

4.之后關閉服務

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

RegisterOnShutdown方法

Go1.9之后有了RegisterOnShutdown方法,用來在優雅的關閉服務的同時處理一些退出任務。

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

關于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進行注冊之后,這些函數被放入一個函數切片中,并在Shutdown被調用的時候,為每個函數啟動了一個goroutine進行處理。

但由于沒有進行后續處理,于是這里有個小問題,Shutdown是不等待這些處理函數結束的,就可能比這些處理函數先完成并進而結束程序。

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
}

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

sync.WaitGroup處理退出函數

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

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

我們在RegisterOnShutdown時使用了time.Sleep(3 * time.Second)來模擬一個長時間的退出程序,并且在"Shutdown finish"之后進行等待,等待退出程序完成任務。

執行日志如下:

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

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

另外,如果在服務運行的過程中需要啟動一些其他的任務,也可以使用

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

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

以上就是go關閉Graceful Shutdown服務的幾種方法的簡略介紹,當然詳細使用上面的不同還得要大家自己使用過才領會。如果想了解更多,歡迎關注億速云行業資訊頻道哦!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

云阳县| 自贡市| 昌宁县| 扬中市| 资溪县| 阿鲁科尔沁旗| 呼伦贝尔市| 康乐县| 浠水县| 同心县| 翁牛特旗| 惠州市| 察雅县| 庄河市| 确山县| 无棣县| 屏山县| 车险| 偏关县| 张家港市| 崇明县| 兴化市| 桦川县| 杨浦区| 永清县| 红河县| 万州区| 仙居县| 包头市| 仁怀市| 广东省| 额济纳旗| 泽普县| 遂宁市| 泗阳县| 昌都县| 茶陵县| 碌曲县| 宜兴市| 彝良县| 哈巴河县|