2024-03-19 02:45:09 +08:00

114 lines
2.2 KiB
Go

package main
import (
"context"
"flag"
"net"
"net/http"
"os"
"os/exec"
"os/signal"
"sync"
"syscall"
"time"
)
// 一个停止的信号量
var (
isStop bool
lock sync.WaitGroup
server *http.Server
listener net.Listener
isReload bool
)
func init() {
flag.BoolVar(&isReload, "reload", false, "")
flag.Parse()
}
// 优雅停止中间件
func GracefulStop(handel func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
return func(writer http.ResponseWriter, request *http.Request) {
lock.Add(1)
if isStop {
//不再接收新的请求
writer.WriteHeader(400)
writer.Write([]byte("server is stop"))
} else {
handel(writer, request)
}
lock.Done()
}
}
// 一个会耗时很长的方法
func LongTime(writer http.ResponseWriter, request *http.Request) {
time.Sleep(time.Second * 5)
writer.Write([]byte("Hello"))
}
func Normal(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("Hello"))
}
func main() {
http.HandleFunc("/normal", Normal)
http.HandleFunc("/long-time", GracefulStop(LongTime))
//监听信号
go func() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1)
for {
sign := <-ch
ctx, _ := context.WithTimeout(context.Background(), 20*time.Second)
switch sign {
case syscall.SIGINT, syscall.SIGTERM:
{
println("stop...")
//停止
isStop = true
lock.Wait()
//结束
signal.Stop(ch)
server.Shutdown(ctx)
println("stop")
return
}
case syscall.SIGUSR1:
{
println("reload...")
//热重启
tl, _ := listener.(*net.TCPListener)
f, _ := tl.File()
cmd := exec.Command(os.Args[0], "--reload")
cmd.Stdout = os.Stdout
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
cmd.ExtraFiles = []*os.File{f}
cmd.Start()
signal.Stop(ch)
server.Shutdown(ctx)
println("father stop")
return
}
}
}
}()
if isReload {
f := os.NewFile(3, "")
listener, _ = net.FileListener(f)
println("child start")
} else {
listener, _ = net.Listen("tcp", ":8080")
}
server = &http.Server{
Addr: ":8080",
Handler: nil,
}
server.Serve(listener)
}