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

gin優(yōu)雅地關(guān)機(jī)或重啟的實(shí)現(xiàn)

 更新時(shí)間:2026年07月21日 09:38:56   作者:cocoCola91667  
我們編寫的Web項(xiàng)目部署之后,經(jīng)常會因?yàn)樾枰M(jìn)行配置變更或功能迭代而重啟服務(wù),單純的kill -9 pid的方式會強(qiáng)制關(guān)閉進(jìn)程,這樣就會導(dǎo)致服務(wù)端當(dāng)前正在處理的請求失敗,那有沒有更優(yōu)雅的方式來實(shí)現(xiàn)關(guān)機(jī)h或者重啟,下面就來詳細(xì)的了解一下

我們編寫的Web項(xiàng)目部署之后,經(jīng)常會因?yàn)樾枰M(jìn)行配置變更或功能迭代而重啟服務(wù),單純的kill -9 pid的方式會強(qiáng)制關(guān)閉進(jìn)程,這樣就會導(dǎo)致服務(wù)端當(dāng)前正在處理的請求失敗,那有沒有更優(yōu)雅的方式來實(shí)現(xiàn)關(guān)機(jī)或重啟呢?

閱讀本文需要了解一些UNIX系統(tǒng)中信號的概念,請?zhí)崆安殚嗁Y料預(yù)習(xí)。

優(yōu)雅地關(guān)機(jī)

優(yōu)雅關(guān)機(jī)就是服務(wù)端關(guān)機(jī)命令發(fā)出后不是立即關(guān)機(jī),而是等待當(dāng)前還在處理的請求全部處理完畢后再退出程序,是一種對客戶端友好的關(guān)機(jī)方式。而執(zhí)行Ctrl+C關(guān)閉服務(wù)端時(shí),會強(qiáng)制結(jié)束進(jìn)程導(dǎo)致正在訪問的請求出現(xiàn)問題。

如何實(shí)現(xiàn)優(yōu)雅關(guān)機(jī)?

Go 1.8版本之后, http.Server 內(nèi)置的 Shutdown() 方法就支持優(yōu)雅地關(guān)機(jī),具體示例如下:

// +build go1.8
package main

import (
    "context"
    "log"
    "net/http"
    "os"
    "os/signal"
    "syscall"
    "time"

    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()
    router.GET("/", func(c *gin.Context) {
        time.Sleep(5 * time.Second)
        c.String(http.StatusOK, "Welcome Gin Server")
    })

    srv := &http.Server{
        Addr:    ":8080",
        Handler: router, // 將router注冊到server里面
    }

    go func() {
        // 開啟一個(gè)goroutine啟動服務(wù)
        // 如果不開啟ListenAndServe就會一直接收請求處理請求,代碼就不會往下執(zhí)行
        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("listen: %s\n", err)
        }
    }()

    // 等待中斷信號來優(yōu)雅地關(guān)閉服務(wù)器,為關(guān)閉服務(wù)器操作設(shè)置一個(gè)5秒的超時(shí)
    quit := make(chan os.Signal, 1) // 創(chuàng)建一個(gè)接收信號的通道
    // kill 默認(rèn)會發(fā)送 syscall.SIGTERM 信號
    // kill -2 發(fā)送 syscall.SIGINT 信號,我們常用的Ctrl+C就是觸發(fā)系統(tǒng)SIGINT信號
    // kill -9 發(fā)送 syscall.SIGKILL 信號,但是不能被捕獲,所以不需要添加它
    // signal.Notify把收到的 syscall.SIGINT或syscall.SIGTERM 信號轉(zhuǎn)發(fā)給quit
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)  // 此處不會阻塞
    <-quit  // 阻塞在此,當(dāng)接收到上述兩種信號時(shí)才會往下執(zhí)行
    log.Println("Shutdown Server ...")
    // 創(chuàng)建一個(gè)5秒超時(shí)的context
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    // 5秒內(nèi)優(yōu)雅關(guān)閉服務(wù)(將未處理完的請求處理完再關(guān)閉服務(wù)),超過5秒就超時(shí)退出
    if err := srv.Shutdown(ctx); err != nil {
        log.Fatal("Server Shutdown: ", err)
    }

    log.Println("Server exiting")
}

如何驗(yàn)證優(yōu)雅關(guān)機(jī)的效果呢?

上面的代碼運(yùn)行后會在本地的8080端口開啟一個(gè)web服務(wù),它只注冊了一條路由/,后端服務(wù)會先sleep 5秒鐘然后才返回響應(yīng)信息。

我們按下Ctrl+C時(shí)會發(fā)送syscall.SIGINT來通知程序優(yōu)雅關(guān)機(jī),具體做法如下:

  1. 打開終端,編譯并執(zhí)行上面的代碼
  2. 打開一個(gè)瀏覽器,訪問127.0.0.1:8080/,此時(shí)瀏覽器白屏等待服務(wù)端返回響應(yīng)。
  3. 在終端迅速執(zhí)行Ctrl+C命令給程序發(fā)送syscall.SIGINT信號
  4. 此時(shí)程序并不立即退出而是等我們第2步的響應(yīng)返回之后再退出,從而實(shí)現(xiàn)優(yōu)雅關(guān)機(jī)。

優(yōu)雅關(guān)機(jī)實(shí)現(xiàn)了,那么該如何實(shí)現(xiàn)優(yōu)雅重啟呢?

優(yōu)雅地重啟

我們可以使用 fvbock/endless 來替換默認(rèn)的 ListenAndServe啟動服務(wù)來實(shí)現(xiàn), 示例代碼如下:

package main

import (
    "log"
    "net/http"
    "time"

    "github.com/fvbock/endless"
    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()
    router.GET("/", func(c *gin.Context) {
        time.Sleep(5 * time.Second)
        c.String(http.StatusOK, "hello gin!")
    })
    // 默認(rèn)endless服務(wù)器會監(jiān)聽下列信號:
    // syscall.SIGHUP,syscall.SIGUSR1,syscall.SIGUSR2,syscall.SIGINT,syscall.SIGTERM和syscall.SIGTSTP
    // 接收到 SIGHUP 信號將觸發(fā)`fork/restart` 實(shí)現(xiàn)優(yōu)雅重啟(kill -1 pid會發(fā)送SIGHUP信號)
    // 接收到 syscall.SIGINT或syscall.SIGTERM 信號將觸發(fā)優(yōu)雅關(guān)機(jī)
    // 接收到 SIGUSR2 信號將觸發(fā)HammerTime
    // SIGUSR1 和 SIGTSTP 被用來觸發(fā)一些用戶自定義的hook函數(shù)
    if err := endless.ListenAndServe(":8080", router); err!=nil{
        log.Fatalf("listen: %s\n", err)
    }

    log.Println("Server exiting")
}

補(bǔ)充

# 將main.go運(yùn)行起來
go run main.go

# 假設(shè)你當(dāng)前在 graceful_restart_demo 目錄下執(zhí)行
go build
# 生成的可執(zhí)行文件叫 graceful_restart_demo

# 指定程序名
go build -o graceful_restart
# -o?是?output(輸出)的縮寫,用來指定生成的文件的名字。這里指定了生成的程序名叫?graceful_restart

# 直接可以將這個(gè)可執(zhí)行文件運(yùn)行起來
./graceful_restart

如何驗(yàn)證優(yōu)雅重啟的效果呢?

我們通過執(zhí)行kill -1 pid命令發(fā)送syscall.SIGINT來通知程序優(yōu)雅重啟,具體做法如下:

  1. 打開終端,go build -o graceful_restart編譯并執(zhí)行./graceful_restart,終端輸出當(dāng)前pid(假設(shè)為43682)
  2. 將代碼中處理請求函數(shù)返回的hello gin!修改為hello q1mi!,再次編譯go build -o graceful_restart
  3. 打開一個(gè)瀏覽器,訪問127.0.0.1:8080/,此時(shí)瀏覽器白屏等待服務(wù)端返回響應(yīng)。
  4. 在終端迅速執(zhí)行kill -1 43682命令給程序發(fā)送syscall.SIGHUP信號
  5. 等第3步瀏覽器收到響應(yīng)信息hello gin!后再次訪問127.0.0.1:8080/會收到hello q1mi!的響應(yīng)。
  6. 在不影響當(dāng)前未處理完請求的同時(shí)完成了程序代碼的替換,實(shí)現(xiàn)了優(yōu)雅重啟。

但是需要注意的是,此時(shí)程序的PID變化了,因?yàn)閑ndless 是通過fork子進(jìn)程處理新請求,待原進(jìn)程處理完當(dāng)前請求后再退出的方式實(shí)現(xiàn)優(yōu)雅重啟的。所以當(dāng)你的項(xiàng)目是使用類似supervisor的軟件管理進(jìn)程時(shí)就不適用這種方式了。

無論是優(yōu)雅關(guān)機(jī)還是優(yōu)雅重啟歸根結(jié)底都是通過監(jiān)聽特定系統(tǒng)信號,然后執(zhí)行一定的邏輯處理保障當(dāng)前系統(tǒng)正在處理的請求被正常處理后再關(guān)閉當(dāng)前進(jìn)程。使用優(yōu)雅關(guān)機(jī)還是使用優(yōu)雅重啟以及怎么實(shí)現(xiàn),這就需要根據(jù)項(xiàng)目實(shí)際情況來決定了。

到此這篇關(guān)于gin優(yōu)雅地關(guān)機(jī)或重啟的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)gin 關(guān)機(jī)或重啟內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • golang中json和struct的使用說明

    golang中json和struct的使用說明

    這篇文章主要介紹了golang中json和struct的使用說明,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • go語言的變量定義示例詳解

    go語言的變量定義示例詳解

    這篇文章主要為大家介紹了go語言的變量定義示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Golang實(shí)現(xiàn)支付寶沙箱支付的方法步驟

    Golang實(shí)現(xiàn)支付寶沙箱支付的方法步驟

    本文主要介紹了Golang實(shí)現(xiàn)支付寶沙箱支付的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Golang使用原生http實(shí)現(xiàn)中間件的代碼詳解

    Golang使用原生http實(shí)現(xiàn)中間件的代碼詳解

    中間件(middleware):常被用來做認(rèn)證校驗(yàn)、審計(jì)等,家常用的Iris、Gin等web框架,都包含了中間件邏輯,但有時(shí)我們引入該框架顯得較為繁重,本文將介紹通過golang原生http來實(shí)現(xiàn)中間件操作,需要的朋友可以參考下
    2024-05-05
  • Golang實(shí)現(xiàn)自己的Redis(TCP篇)實(shí)例探究

    Golang實(shí)現(xiàn)自己的Redis(TCP篇)實(shí)例探究

    這篇文章主要介紹了Golang實(shí)現(xiàn)自己的Redis(TCP篇)實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Go語言中slice類型的使用小結(jié)

    Go語言中slice類型的使用小結(jié)

    本文主要介紹了Go語言中slice類型的使用小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2026-03-03
  • 詳解如何在Go中循環(huán)中使用Defer關(guān)鍵字示例詳解

    詳解如何在Go中循環(huán)中使用Defer關(guān)鍵字示例詳解

    這篇文章主要為大家介紹了詳解如何在Go中循環(huán)中使用Defer關(guān)鍵字示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • go語法入門泛型type?parameters簡稱T(類型形參)兩種場景使用

    go語法入門泛型type?parameters簡稱T(類型形參)兩種場景使用

    這篇文章主要為大家介紹了go語法入門泛型type?parameters簡稱T(類型形參)兩種場景使用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • go 協(xié)程返回值處理操作

    go 協(xié)程返回值處理操作

    這篇文章主要介紹了go 協(xié)程返回值處理操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • go map range遍歷刪除問題及解決

    go map range遍歷刪除問題及解決

    這段文章主要討論了Go語言中使用map數(shù)據(jù)結(jié)構(gòu)的方法及其遍歷和刪除元素的操作,特別強(qiáng)調(diào)了直接將map賦值為nil以供垃圾回收器處理是清空map的最佳實(shí)踐
    2026-06-06

最新評論

广昌县| 丰县| 马龙县| 江山市| 武山县| 朔州市| 宣汉县| 荥阳市| 龙游县| 荆门市| 临城县| 屯门区| 珲春市| 稷山县| 泰州市| 都匀市| 星座| 屏东市| 阿瓦提县| 武胜县| 分宜县| 和田市| 松潘县| 建水县| 漾濞| 哈尔滨市| 七台河市| 福贡县| 油尖旺区| 石棉县| 安多县| 浙江省| 甘南县| 武穴市| 同心县| 金山区| 宁乡县| 康马县| 萍乡市| 夏津县| 烟台市|