關於gin利用src.Shutdown進行平滑關閉原理分享

滾球獸進化發表於2021-11-27

官閘道器於重啟的例子優雅地重啟或停止 | Gin Web Framework (gin-gonic.com)

gin利用src.Shutdown的關閉的行為可以這麼看待,一件是當前是否沒有連結了,另一件事情是你傳入了一個最大超時時間是否已到,如果到了也停止。結束在這個函式裡面的標誌,表現在 srv.Shutdown() 返回了結果。

gin 平滑關閉原理

  • src.Shutdown 關閉外部連線,
  • gin建立了一個定時器
  • 檢查當前是否還有執行著的連線,如果沒有則 return
    否則如果有進行select操作。
  • select 中同時檢測兩個channel 第一個是 context.WithTimeout ,他會在5s後傳送,如果他收到了結果會直接 return
  • 另一個是 就是定時器的channel,如果收到的是定時器的 channel ,並不會return,而是進行再一次檢查。如果還是有連結存在,就會繼續下一輪的select

其中下面涼快程式碼有助於我們理解它的實現。

這是一段關於context.WithTimeout的用法,效果是5後可以從channel收到值(下文中沒有取,收到直接拋棄了)

            fmt.Println(time.Now().String())
            ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
            defer cancel()
            <-ctx.Done()
            fmt.Println(time.Now().String())

這是一段關於同時等待兩個channel的程式碼

ch := make(chan int)
ch2 := make(chan int)
go func() {
    for i := 5; i > 0; i-- {
        time.Sleep(time.Second * 1)
    }
    ch <- 1
}()
go func() {
    time.Sleep(time.Second * 10)
    ch2 <- 1
}()

select {
    case <-ch:
    fmt.Println("收到ch")
    break
    case <-ch2:
    fmt.Println("收到ch2")
    break
}
//收到後的操作

原始碼部分擷取

·····
    timer := time.NewTimer(nextPollInterval())
    defer timer.Stop()
    for {
        if srv.closeIdleConns() && srv.numListeners() == 0 {
            return lnerr
        }
        select {
        case <-ctx.Done():
            return ctx.Err()
        case <-timer.C:
            timer.Reset(nextPollInterval())
        }
    }
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章