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

Go?Web開發(fā)之Gin多服務(wù)配置及優(yōu)雅關(guān)閉平滑重啟實現(xiàn)方法

 更新時間:2024年01月31日 10:15:39   作者:WeiyiGeek?全棧工程師  
這篇文章主要為大家介紹了Go?Web開發(fā)之Gin多服務(wù)配置及優(yōu)雅關(guān)閉平滑重啟實現(xiàn)方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

如何自定義Gin服務(wù)配置及其啟動多個服務(wù)?

描述: 在Gin的生產(chǎn)環(huán)境中通常會自定義HTTP配置以達到最優(yōu)性能,此處我們簡單一下 Server 結(jié)構(gòu)體中可配置的參數(shù)項。

// A Server defines parameters for running an HTTP server.
// The zero value for Server is a valid configuration.
type Server struct {
  // 配置監(jiān)聽地址:端口,默認是:8080
	Addr string
  // 要調(diào)用的處理程序,http.DefaultServeMux如果為nil
	Handler Handler
  // 如果為true,則將“OPTIONS*”請求傳遞給Handler 
	DisableGeneralOptionsHandler bool
  // 提供TLS配置
	TLSConfig *tls.Config
  //讀取整個請求(包括正文)的最長持續(xù)時間。
	ReadTimeout time.Duration
  // 讀取整請求(Header)的最長持續(xù)時間。
	ReadHeaderTimeout time.Duration
  // 超時寫入響應(yīng)之前的最長持續(xù)時間
	WriteTimeout time.Duration
  // 啟用保持活動時等待下一個請求的最長時間
	IdleTimeout time.Duration
  // 控制服務(wù)器解析請求標頭的鍵和值(包括請求行)時讀取的最大字節(jié)數(shù) (通常情況下不進行設(shè)置) 
	MaxHeaderBytes int
  // 在發(fā)生ALPN協(xié)議升級時接管所提供TLS連接的所有權(quán)。
	TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
  // 指定了一個可選的回調(diào)函數(shù),當客戶端連接更改狀態(tài)時調(diào)用該函數(shù)
	ConnState func(net.Conn, ConnState)
  // 為接受連接的錯誤、處理程序的意外行為以及潛在的FileSystem錯誤指定了一個可選的記錄器
  ErrorLog *log.Logger
  // 返回/此服務(wù)器上傳入請求的基本上下文
	BaseContext func(net.Listener) context.Context
  // 指定一個函數(shù)來修改用于新連接c的上下
	ConnContext func(ctx context.Context, c net.Conn) context.Context
  // 當服務(wù)器處于關(guān)閉狀態(tài)時為true
	inShutdown atomic.Bool
	disableKeepAlives atomic.Bool
	nextProtoOnce     sync.Once // guards setupHTTP2_* init
	nextProtoErr      error     // result of http2.ConfigureServer if used
	mu         sync.Mutex
	listeners  map[*net.Listener]struct{}
	activeConn map[*conn]struct{}
	onShutdown []func()
	listenerGroup sync.WaitGroup
}

模塊更新

go get -u golang.org/x/sync/errgroup
go mod tidy

示例代碼:

package main
import (
	"log"
	"net/http"
	"time"
	"github.com/gin-gonic/gin"
	"golang.org/x/sync/errgroup"
)
// 處理屬于同一總體任務(wù)的子任務(wù)的goroutine的集合
var (
	g errgroup.Group
)
// s2 Gin 服務(wù)的 Handler
func router02() http.Handler {
	e := gin.New()
	e.Use(gin.Recovery())
	e.GET("/", func(c *gin.Context) {
		c.JSON(
			http.StatusOK,
			gin.H{
				"code": http.StatusOK,
				"msg":  "Welcome server 02 blog.weiyigeek.top",
			},
		)
	})
	return e
}
func main() {
	// Default返回一個Engine實例,該實例已連接Logger和Recovery中間件。
	router := gin.Default()
	// Gin 服務(wù)s1.用于運行HTTP服務(wù)器的參數(shù) (常規(guī)參數(shù))
	s1 := &http.Server{
		// Gin運行的監(jiān)聽端口
		Addr: ":8080",
		// 要調(diào)用的處理程序,http.DefaultServeMux如果為nil
		Handler: router,
		// ReadTimeout是讀取整個請求(包括正文)的最長持續(xù)時間。
		ReadTimeout: 5 * time.Second,
		// WriteTimeout是超時寫入響應(yīng)之前的最長持續(xù)時間
		WriteTimeout: 10 * time.Second,
		// MaxHeaderBytes控制服務(wù)器解析請求標頭的鍵和值(包括請求行)時讀取的最大字節(jié)數(shù) (通常情況下不進行設(shè)置)
		MaxHeaderBytes: 1 << 20,
	}
	// Go在一個新的goroutine中調(diào)用給定的函數(shù),此處將Go語言的并發(fā)體現(xiàn)的淋漓盡致。
	g.Go(func() error {
		return s1.ListenAndServe()
	})
	// 配置Gin中間件
	// Recovery返回一個中間件,該中間件可以從任何exception中恢復,并在出現(xiàn)exception時寫入500。
	router.Use(gin.Recovery())
	// 服務(wù)s1的路由
	router.GET("/", func(c *gin.Context) {
		c.JSON(
			http.StatusOK,
			gin.H{
				"code": http.StatusOK,
				"msg":  "Welcome server 01 www.weiyigeek.top",
			},
		)
	})
	// Gin 服務(wù)s1.定義了不同的監(jiān)聽端口以及Handler
	s2 := &http.Server{
		Addr:         ":8081",
		Handler:      router02(),
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}
	g.Go(func() error {
		return s2.ListenAndServe()
	})
	if err := g.Wait(); err != nil {
		log.Fatal(err)
	}
}

執(zhí)行結(jié)果:

如何優(yōu)雅的關(guān)閉或者重啟Gin應(yīng)用程序?

1.使用 chan 通道監(jiān)聽中斷信號(SIGINT和SIGTERM)

描述: 在Go Gin中,可以使用以下代碼實現(xiàn)優(yōu)雅地重啟或停止, 確保所有連接都被正確關(guān)閉,避免數(shù)據(jù)丟失或損壞。

代碼示例:

package main

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

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

func main() {
	// 創(chuàng)建 Gin 實例
	router := gin.Default()

	// 添加路由
	router.GET("/", func(c *gin.Context) {
		c.String(http.StatusOK, "Hello, World! weiyigeek.top")
	})

	// 創(chuàng)建 HTTP Server
	srv := &http.Server{
		Addr:    ":8080",
		Handler: router,
	}

  // 開啟一個goroutine啟動服務(wù) 啟動 HTTP Server
	go func() {
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %s\n", err)
		}
	}()

	// 等待中斷信號
	quit := make(chan os.Signal)
	// 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 秒的超時上下文
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// 關(guān)閉 HTTP Server
  // 	// 5秒內(nèi)優(yōu)雅關(guān)閉服務(wù)(將未處理完的請求處理完再關(guān)閉服務(wù)),超過5秒就超時退出
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal("Server Shutdown:", err)
	}
	log.Println("Server exiting")
}

代碼解析:

首先創(chuàng)建了一個Gin實例和一個HTTP Server,然后啟動HTTP Server。接下來,使用signal.Notify()函數(shù)監(jiān)聽中斷信號(SIGINT和SIGTERM),當接收到中斷信號時,服務(wù)器會進入優(yōu)雅關(guān)閉流程,即先關(guān)閉HTTP Server,然后等待5秒鐘,最后退出程序。

在關(guān)閉HTTP Server時,我們使用了srv.Shutdown()函數(shù),它會優(yōu)雅地關(guān)閉HTTP Server并等待所有連接關(guān)閉。如果在5秒鐘內(nèi)沒有關(guān)閉完所有連接,函數(shù)會返回錯誤。

知識補充: 

使用os/signal包實現(xiàn)對信號的處理, 最常見的信號列表。

2.使用 os/exec 包來執(zhí)行Gin平滑重啟

描述: 在Linux的Go-gin環(huán)境中我們可以使用 os/exec 包來執(zhí)行重啟命令,然后在 Gin 中定義一個路由,使得訪問該路由時會執(zhí)行重啟命令。

代碼示例:

package main

import (
  "fmt"
  "net/http"
  "os"
  "os/exec"

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

func main() {
  r := gin.Default()
  // 重啟的路由 /restart
  r.GET("/restart", func(c *gin.Context) {
    cmd := exec.Command("killall", "-HUP", "appweiyigeek")
    err := cmd.Run()
    if err != nil {
      fmt.Println("Error executing restart command:", err)
      c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to restart Gin server."})
      return
    }
    c.JSON(http.StatusOK, gin.H{"message": "Gin server restarted successfully."})
  })

  r.Run(":8080")
}

編譯執(zhí)行:

go build ./main.go -o appweiyigeek
./appweiyigeek

在上面的例子中,我們定義了一個路由 /restart,當訪問該路由時,它會執(zhí)行 killall -HUP appweiyigeek 命令來重啟 Gin 服務(wù), 這里的appweiyigeek應(yīng)該替換為你實際的 Gin 應(yīng)用程序的名稱。

溫馨提示: 此種重啟方式可能會導致請求失敗或者超時,因為它會強制關(guān)閉正在處理的連接, 如果你需要更加優(yōu)雅的重啟方式,可以考慮使用優(yōu)雅重啟的方式。

3.使用 fvbock/endless 包實現(xiàn)訪問指定路由平滑重啟Gin服務(wù)

描述: 由于endless在windows環(huán)境是不支持,所以博主針對下述代碼在Linux環(huán)境下載并編譯成二進制文件打包到Linux環(huán)境運行進行驗證。

依賴下載:

go get -u github.com/fvbock/endless
go mod tidy

代碼示例:

package main
import (
	"fmt"
	"log"
	"net/http"
	"os/exec"
	"strconv"
	"syscall"
	"github.com/fvbock/endless"
	"github.com/gin-gonic/gin"
)
func main() {
	pid := syscall.Getpid()
	// 1.默認的Gin引擎
	router := gin.Default()
	// 傳統(tǒng)方式
	// server := &http.Server{
	// 	Addr:         ":8080",
	// 	Handler:      router,
	// 	ReadTimeout:  5 * time.Second,
	// 	WriteTimeout: 10 * time.Second,
	// }
	// 2.獲取 Pid
	router.GET("/pid", func(c *gin.Context) {
		pid = syscall.Getpid()
		fmt.Println("Pid:", pid)
		c.JSON(http.StatusOK,
			gin.H{
				"code": http.StatusOK,
				"msg":  fmt.Sprintf("Gin Server Pid ->  %d.", pid),
			})
	})
	// 3.重啟 Gin 服務(wù)
	router.POST("/restart", func(c *gin.Context) {
		pid = syscall.Getpid()
		fmt.Println("Restarting Gin Server.......", pid)
		err := exec.Command("kill", "-1", strconv.Itoa(pid)).Run()
		if err != nil {
			fmt.Println("Error executing restart command:", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to restart Gin server."})
			return
		}
		c.JSON(http.StatusOK, gin.H{"message": "Gin server restarted successfully.", "pid": pid})
	})
	// 4.使用endless偵聽TCP網(wǎng)絡(luò)地址addr,然后使用處理程序調(diào)用Serve來處理傳入連接上的請求
	err := endless.ListenAndServe(":8080", router)
	if err != nil || err != http.ErrServerClosed {
		log.Println("err:", err)
	}
	// 5.引入了endless擴展,將原本的Run方式啟動項目改成了ListenAndServe方式所有此處主席掉
	// router.Run(":8080")
}

編譯構(gòu)建:

# 切換編譯在Linux平臺的64位可執(zhí)行程序環(huán)境
go env -w CGO_ENABLED=0 GOOS=linux GOARCH=amd64

# 編譯
go build -o endless-test-1 .\main.go

# 執(zhí)行驗證
chmod +x endless-test-1
nohup ./endless-test-1 &
[1] 1147978

執(zhí)行效果:

# GET 請求 10.20.176.101:8080/pid
# POST 請求 10.20.176.101:8080/restart

請求restart后可以看見go-gin已經(jīng)平滑重啟了是不是很方便,效果如下。

以上就是Go Web開發(fā)之Gin多服務(wù)配置及優(yōu)雅關(guān)閉平滑重啟實現(xiàn)方法的詳細內(nèi)容,更多關(guān)于Go Web Gin多服務(wù)配置的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語言操作MySql數(shù)據(jù)庫的詳細指南

    Go語言操作MySql數(shù)據(jù)庫的詳細指南

    數(shù)據(jù)的持久化是程序中必不可少的,所以編程語言中對數(shù)據(jù)庫的操作是非常重要的一塊,這篇文章主要給大家介紹了關(guān)于Go語言操作MySql數(shù)據(jù)庫的相關(guān)資料,需要的朋友可以參考下
    2023-10-10
  • mac下安裝golang框架iris的方法

    mac下安裝golang框架iris的方法

    這篇文章主要介紹了mac下安裝golang框架iris的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • 一文詳解Golang的模塊版本管理與語義版本控制

    一文詳解Golang的模塊版本管理與語義版本控制

    在Golang中,模塊(module)是Go 1.11版本引入的依賴管理系統(tǒng),幫助開發(fā)者管理項目的依賴,在Go模塊推出之前,開發(fā)者通常使用GOPATH和vendor目錄來管理項目的依賴,本文將給大家詳細介紹Golang的模塊版本管理與語義版本控制,需要的朋友可以參考下
    2023-12-12
  • Goland中Protobuf的安裝、配置和使用

    Goland中Protobuf的安裝、配置和使用

    本文記錄了mac環(huán)境下protobuf的編譯安裝,并通過一個示例來演示proto自動生成go代碼,本文使用的mac?os?12.3系統(tǒng),不建議使用homebrew安裝,系統(tǒng)版本太高,會安裝報錯,所以自己下載新版壓縮包編譯構(gòu)建安裝
    2022-05-05
  • golang os.Eixt使用示例

    golang os.Eixt使用示例

    在Go語言中,os.Exit函數(shù)用于立即終止程序并返回一個指定的退出狀態(tài)碼,本文就來介紹一下golang os.Eixt使用,具有一定的參考價值,感興趣的可以了解一下
    2024-10-10
  • Go標準庫日志打印及同時輸出到控制臺與文件

    Go標準庫日志打印及同時輸出到控制臺與文件

    Go語言內(nèi)置的log包實現(xiàn)了簡單的日志服務(wù),下面這篇文章主要給大家介紹了關(guān)于Go標準庫日志打印及同時輸出到控制臺與文件的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-11-11
  • 使用go讀取gzip格式的壓縮包的操作

    使用go讀取gzip格式的壓縮包的操作

    這篇文章主要介紹了使用go讀取gzip格式的壓縮包的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang?單元測試和基準測試實例詳解

    Golang?單元測試和基準測試實例詳解

    這篇文章主要為大家介紹了Golang?單元測試和基準測試實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • 使用Golang獲取音視頻時長信息的示例代碼

    使用Golang獲取音視頻時長信息的示例代碼

    這篇文章主要介紹了如何使用Golang獲取音視頻時長信息,文中通過代碼示例講解的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下
    2024-03-03
  • GO語言求100以內(nèi)的素數(shù)

    GO語言求100以內(nèi)的素數(shù)

    這篇文章主要介紹了GO語言求100以內(nèi)的素數(shù),主要通過篩選法來實現(xiàn),涉及GO語言基本的循環(huán)與函數(shù)調(diào)用方法,需要的朋友可以參考下
    2014-12-12

最新評論