golang 監(jiān)聽服務(wù)的信號(hào),實(shí)現(xiàn)平滑啟動(dòng),linux信號(hào)說明詳解
監(jiān)聽服務(wù)的信號(hào),實(shí)現(xiàn)平滑啟動(dòng),linux信號(hào)說明

package main
import (
"context"
"fmt"
"golang.org/x/sync/errgroup"
"net/http"
"os"
"os/signal"
"syscall"
)
func main() {
g, ctx := errgroup.WithContext(context.Background())
fmt.Println("服務(wù)啟動(dòng)start!")
addr := ":9091"
s :=&http.Server{
Addr: addr,
Handler:http.DefaultServeMux,
}
g.Go(func() error {
http.HandleFunc("/test1", func(writer http.ResponseWriter, request *http.Request) {
fmt.Println("tes1")
writer.Write([]byte("tes1"))
})
return s.ListenAndServe()
})
g.Go(func() error {
exit := make(chan os.Signal)
//監(jiān)聽 Ctrl+C 信號(hào)
signal.Notify(exit, syscall.SIGINT, syscall.SIGTERM)
select {
case <-exit:
fmt.Println("進(jìn)程已被取消~")
return s.Shutdown(ctx)
}
})
err := g.Wait()
if err != nil {
fmt.Println(err)
}
fmt.Println("服務(wù)啟動(dòng)成功!")
if ctx.Err() !=nil {
fmt.Println(ctx.Err())
fmt.Println("服務(wù)關(guān)閉成功!")
os.Exit(0)
}
}
補(bǔ)充:golang http服務(wù)實(shí)現(xiàn)平滑重啟
看代碼吧~
package main
import (
"context"
"encoding/json"
"fmt"
"math/rand"
"net/http"
"os"
"os/signal"
"time"
)
var logChan = make(chan map[string]interface{})
var requestStatusMap = map[int]bool{}
var done = make(chan bool, 1)
var quit = make(chan os.Signal, 1)
//為什么這樣可以平滑重啟?
// 正常情況下是server.ListenAndServe() 這個(gè)位置hang住整個(gè)進(jìn)程的
// 可以把這個(gè)程序看成兩部分,1個(gè)是web服務(wù)的監(jiān)聽部分,一個(gè)是處理部分, 如果web服務(wù)器不開啟了,那么就不能處理新進(jìn)來的請(qǐng)求了(可以理解為一個(gè)帶路的)
// 真正讓這個(gè)請(qǐng)求斷掉 是因?yàn)橹鬟M(jìn)程(main)被kill
// 所以平滑重啟的原理就是,先kill掉web服務(wù)器,不讓新的請(qǐng)求進(jìn)來,等現(xiàn)有的全部請(qǐng)求完了,然后結(jié)束當(dāng)前進(jìn)程
func main() {
server := newServer()
signal.Notify(quit, os.Interrupt)
go monitorKill(server, quit)
server.ListenAndServe()
<-done
}
func newServer() *http.Server {
router := http.NewServeMux()
router.HandleFunc("/hello", sayHello)
return &http.Server{
Addr: ":8262",
Handler: router,
}
}
func monitorKill(server *http.Server, quit <-chan os.Signal) {
<-quit
go shutDown(server)
for {
if len(requestStatusMap) != 0 {
fmt.Println("目前還有進(jìn)行中的請(qǐng)求,請(qǐng)稍等")
time.Sleep(time.Second * 1)
continue
} else {
close(done)
break
}
}
}
func shutDown(server *http.Server) {
if err := server.Shutdown(context.Background()); err != nil {
fmt.Println(err)
}
}
func sayHello(w http.ResponseWriter, r *http.Request) {
go WriteInfo()//請(qǐng)求寫日志
var uniqueId = GenerateRangeNum(1, 1000)
requestStatusMap[uniqueId] = false
url := r.URL.Path
query := r.URL.RawQuery
method := r.Method
a := map[string] interface{}{
"url" : url,
"method" : method,
"query" : query,
"response": "hello world!",
}
logChan<-a
w.Write([]byte("hello world!"))
time.Sleep(time.Second * 10)
delete(requestStatusMap, uniqueId)
}
func WriteInfo() {
info := <-logChan
fileName := "/tmp/weekhomework.log"
_, err := os.Stat(fileName)
if err != nil || os.IsNotExist(err) {
_, _ = os.Create(fileName)
}
f,err := os.OpenFile(fileName, os.O_WRONLY, 0644)
defer f.Close()
if err !=nil {
fmt.Println(err.Error())
} else {
//追加寫入 為什么O_APPEND 模式無法寫入? todo
n, _ := f.Seek(0, 2)
infostr, _ := json.Marshal(info)
_,err=f.WriteAt([]byte(string(infostr) +"\n"), n)
}
}
func GenerateRangeNum(min int, max int) int {
if min == max {
return min
}
rand.Seed(time.Now().Unix())
randNum := rand.Intn(max-min) + min
return randNum
}
主要思路:
對(duì)于每個(gè)請(qǐng)求都做記錄,處理完成之后做刪除。 用一個(gè)協(xié)程去監(jiān)控中斷信號(hào),有中斷信號(hào)先把http服務(wù)關(guān)閉。
如果這個(gè)時(shí)候還有請(qǐng)求沒有處理完,那么就輪訓(xùn)等待,等全部處理完那么就 發(fā)出終止信號(hào)結(jié)束main進(jìn)程的執(zhí)行
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
go實(shí)現(xiàn)服務(wù)優(yōu)雅關(guān)閉的示例
本文主要介紹了go實(shí)現(xiàn)服務(wù)優(yōu)雅關(guān)閉的示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
Go語言JSON數(shù)據(jù)返回的實(shí)戰(zhàn)案例
本文介紹用Go標(biāo)準(zhǔn)庫構(gòu)建返回JSON的HTTP接口,包括GET請(qǐng)求處理、JSON編碼及響應(yīng)設(shè)置,為RESTful API開發(fā)打下基礎(chǔ),感興趣的可以了解一下2025-08-08
Go底層channel實(shí)現(xiàn)原理及示例詳解
這篇文章主要介紹了Go底層channel實(shí)現(xiàn)原理及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08

