网络编程
位置:首页>> 网络编程>> Go语言>> golang 监听服务的信号,实现平滑启动,linux信号说明详解

golang 监听服务的信号,实现平滑启动,linux信号说明详解

作者:胖达喵  发布时间:2024-05-09 10:00:43 

标签:golang,监听,信号,平滑

监听服务的信号,实现平滑启动,linux信号说明

golang 监听服务的信号,实现平滑启动,linux信号说明详解


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("服务启动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)
//监听 Ctrl+C 信号
signal.Notify(exit, syscall.SIGINT, syscall.SIGTERM)
select {
case <-exit:
fmt.Println("进程已被取消~")
return s.Shutdown(ctx)
}
})
err := g.Wait()
if err != nil {
fmt.Println(err)
}
fmt.Println("服务启动成功!")
if ctx.Err() !=nil {
fmt.Println(ctx.Err())
fmt.Println("服务关闭成功!")
os.Exit(0)
}

}

补充:golang http服务实现平滑重启

看代码吧~


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() 这个位置hang住整个进程的
// 可以把这个程序看成两部分,1个是web服务的监听部分,一个是处理部分, 如果web服务器不开启了,那么就不能处理新进来的请求了(可以理解为一个带路的)
// 真正让这个请求断掉  是因为主进程(main)被kill
// 所以平滑重启的原理就是,先kill掉web服务器,不让新的请求进来,等现有的全部请求完了,然后结束当前进程
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("目前还有进行中的请求,请稍等")
           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()//请求写日志
   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
}

主要思路:

对于每个请求都做记录,处理完成之后做删除。 用一个协程去监控中断信号,有中断信号先把http服务关闭。

如果这个时候还有请求没有处理完,那么就轮训等待,等全部处理完那么就 发出终止信号结束main进程的执行

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。

来源:https://pangda.blog.csdn.net/article/details/116259908

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com