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

使用golang如何優(yōu)雅的關(guān)機或重啟操作示例

 更新時間:2022年04月16日 12:23:38   作者:Jeff的技術(shù)棧  
這篇文章主要為大家介紹了使用golang如何優(yōu)雅的關(guān)機或重啟操作示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪

前言

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

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

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

什么是優(yōu)雅關(guān)機?

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

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

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

// +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,
	}
	go func() {
		// 開啟一個goroutine啟動服務
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %s\n", err)
		}
	}()
	// 等待中斷信號來優(yōu)雅地關(guān)閉服務器,為關(guān)閉服務器操作設置一個5秒的超時
	quit := make(chan os.Signal, 1) // 創(chuàng)建一個接收信號的通道
	// kill 默認會發(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  // 阻塞在此,當接收到上述兩種信號時才會往下執(zhí)行
	log.Println("Shutdown Server ...")
	// 創(chuàng)建一個5秒超時的context
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	// 5秒內(nèi)優(yōu)雅關(guān)閉服務(將未處理完的請求處理完再關(guān)閉服務),超過5秒就超時退出
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal("Server Shutdown: ", err)
	}
	log.Println("Server exiting")
}

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

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

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

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

優(yōu)雅地重啟

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

我們可以使用 fvbock/endless 來替換默認的 ListenAndServe啟動服務來實現(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!")
	})
	// 默認endless服務器會監(jiān)聽下列信號:
	// syscall.SIGHUP,syscall.SIGUSR1,syscall.SIGUSR2,syscall.SIGINT,syscall.SIGTERM和syscall.SIGTSTP
	// 接收到 SIGHUP 信號將觸發(fā)`fork/restart` 實現(xiàn)優(yōu)雅重啟(kill -1 pid會發(fā)送SIGHUP信號)
	// 接收到 syscall.SIGINT或syscall.SIGTERM 信號將觸發(fā)優(yōu)雅關(guān)機
	// 接收到 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")
}

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

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

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

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

總結(jié)

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

以上就是使用golang如何優(yōu)雅的關(guān)機或重啟 的詳細內(nèi)容,更多關(guān)于golang關(guān)機重啟 的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • GO語言不固定參數(shù)函數(shù)與匿名函數(shù)的使用

    GO語言不固定參數(shù)函數(shù)與匿名函數(shù)的使用

    本文主要介紹了GO語言不固定參數(shù)函數(shù)與匿名函數(shù)的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03
  • 使用go操作redis的有序集合(zset)

    使用go操作redis的有序集合(zset)

    這篇文章主要介紹了使用go操作redis的有序集合(zset),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 如何有效控制Go線程數(shù)實例探究

    如何有效控制Go線程數(shù)實例探究

    這篇文章主要為大家介紹了如何有效控制?Go?線程數(shù)的問題探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • Go語言多人聊天室項目實戰(zhàn)

    Go語言多人聊天室項目實戰(zhàn)

    這篇文章主要為大家詳細介紹了Go語言多人聊天室項目實戰(zhàn),實現(xiàn)單撩或多撩等多種功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • golang語言map全方位介紹

    golang語言map全方位介紹

    本文主要介紹了golang語言map全方位介紹,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • golang xorm及time.Time自定義解決json日期格式的問題

    golang xorm及time.Time自定義解決json日期格式的問題

    這篇文章主要介紹了golang xorm及time.Time自定義解決json日期格式的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 詳解MongoDB?Go?Driver如何記錄日志

    詳解MongoDB?Go?Driver如何記錄日志

    這篇文章主要為大家介紹了MongoDB?Go?Driver如何記錄日志詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • 一文帶你輕松理解Go中的內(nèi)存逃逸問題

    一文帶你輕松理解Go中的內(nèi)存逃逸問題

    這篇文章主要給大家介紹Go中的內(nèi)存逃逸問題,文中通過代碼示例講解的非常詳細,對我們的學習或工作有一定的參考價值,感興趣的同學可以跟著小編一起來學習
    2023-06-06
  • golang中一種不常見的switch語句寫法示例詳解

    golang中一種不常見的switch語句寫法示例詳解

    這篇文章主要介紹了golang中一種不常見的switch語句寫法,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-05-05
  • 在go中進行單元測試的案例分享

    在go中進行單元測試的案例分享

    這篇文章主要介紹了使用Go進行單元測試的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-01-01

最新評論

通州区| 湘潭市| 花莲县| 乌兰浩特市| 康平县| 开封县| 闻喜县| 崇信县| 和平县| 赣榆县| 河南省| 北辰区| 余干县| 伊宁县| 长垣县| 财经| 上蔡县| 垣曲县| 新绛县| 土默特左旗| 定州市| 浙江省| 阿坝县| 六盘水市| 高淳县| 广安市| 伊宁县| 青川县| 银川市| 新河县| 湘西| 新巴尔虎左旗| 锡林浩特市| 专栏| 河北区| 临江市| 太和县| 长岛县| 孝义市| 雷州市| 安乡县|