From c739dd0ed693c6703799c3c1a093ed8815c43341 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 14 May 2018 17:35:54 +0800 Subject: [PATCH] =?UTF-8?q?ghttp.Server=E7=83=AD=E9=87=8D=E5=90=AF?= =?UTF-8?q?=E7=89=B9=E6=80=A7=E5=9C=A8=E5=90=8C=E4=B8=80=E8=BF=9B=E7=A8=8B?= =?UTF-8?q?=E5=A4=9AWeb=20Server=E4=B8=8B=E7=9A=84=E7=A8=B3=E5=AE=9A?= =?UTF-8?q?=E6=80=A7=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- g/net/ghttp/ghttp_server.go | 73 ++++++++++--------- g/net/ghttp/ghttp_server_comm_child.go | 14 ++-- g/net/ghttp/ghttp_server_comm_signal_unix.go | 16 ++-- g/net/ghttp/ghttp_server_graceful.go | 13 ++-- .../hot_restart/multi_port_and_server.go | 5 +- geg/net/ghttp/hot_restart/simple.go | 18 ++--- 6 files changed, 73 insertions(+), 66 deletions(-) diff --git a/g/net/ghttp/ghttp_server.go b/g/net/ghttp/ghttp_server.go index 8a88a630c..871ac58ae 100644 --- a/g/net/ghttp/ghttp_server.go +++ b/g/net/ghttp/ghttp_server.go @@ -8,7 +8,6 @@ package ghttp import ( "os" - "net" "sync" "errors" "strings" @@ -241,9 +240,7 @@ func (s *Server) startServer(fdMap listenerFdMap) { } httpsEnabled = len(s.config.HTTPSAddr) > 0 var array []string - var isFd bool if v, ok := fdMap["https"]; ok && len(v) > 0 { - isFd = true array = strings.Split(v, ",") } else { array = strings.Split(s.config.HTTPSAddr, ",") @@ -253,18 +250,25 @@ func (s *Server) startServer(fdMap listenerFdMap) { continue } go func(addrItem string) { - // windows系统不支持文件描述符传递socket通信平滑交接,因此只能完整重启 - if isFd && runtime.GOOS != "windows" { - tArray := strings.Split(addrItem, "#") - server = s.newGracefulServer(tArray[0], gconv.Int(tArray[1])) + fd := 0 + addr := addrItem + array := strings.Split(addrItem, "#") + if len(array) > 1 { + addr = array[0] + // windows系统不支持文件描述符传递socket通信平滑交接,因此只能完整重启 + if runtime.GOOS != "windows" { + fd = gconv.Int(array[1]) + } + } + if fd > 0 { + server = s.newGracefulServer(addr, fd) } else { - server = s.newGracefulServer(addrItem) + server = s.newGracefulServer(addr) } s.servers = append(s.servers, server) if err := server.ListenAndServeTLS(s.config.HTTPSCertPath, s.config.HTTPSKeyPath); err != nil { // 如果非关闭错误,那么提示报错,否则认为是正常的服务关闭操作 if !strings.EqualFold(http.ErrServerClosed.Error(), err.Error()) { - s.servers = s.servers[0 : len(s.servers) - 1] glog.Error(err) } } @@ -279,9 +283,7 @@ func (s *Server) startServer(fdMap listenerFdMap) { s.config.Addr = gDEFAULT_HTTP_ADDR } var array []string - var isFd bool if v, ok := fdMap["http"]; ok && len(v) > 0 { - isFd = true array = strings.Split(v, ",") } else { array = strings.Split(s.config.Addr, ",") @@ -291,18 +293,25 @@ func (s *Server) startServer(fdMap listenerFdMap) { continue } go func(addrItem string) { - // windows系统不支持文件描述符传递socket通信平滑交接,因此只能完整重启 - if isFd && runtime.GOOS != "windows" { - tArray := strings.Split(addrItem, "#") - server = s.newGracefulServer(tArray[0], gconv.Int(tArray[1])) + fd := 0 + addr := addrItem + array := strings.Split(addrItem, "#") + if len(array) > 1 { + addr = array[0] + // windows系统不支持文件描述符传递socket通信平滑交接,因此只能完整重启 + if runtime.GOOS != "windows" { + fd = gconv.Int(array[1]) + } + } + if fd > 0 { + server = s.newGracefulServer(addr, fd) } else { - server = s.newGracefulServer(addrItem) + server = s.newGracefulServer(addr) } s.servers = append(s.servers, server) if err := server.ListenAndServe(); err != nil { // 如果非关闭错误,那么提示报错,否则认为是正常的服务关闭操作 if !strings.EqualFold(http.ErrServerClosed.Error(), err.Error()) { - s.servers = s.servers[0 : len(s.servers) - 1] glog.Error(err) } } @@ -325,34 +334,26 @@ func (s *Server) Shutdown() { // 获取当前监听的文件描述符信息,构造成map返回 func (s *Server) getListenerFdMap() map[string]string { m := map[string]string { - "http" : "", "https" : "", + "http" : "", } + // s.servers是从HTTPS到HTTP优先级遍历,解析的时候也应当按照这个顺序读取fd for _, v := range s.servers { - //switch l := v.listener.(type) { - //case *net.TCPListener: - //default: - // - // tls.NewListener(ln, config) - // - //} - if f, e := v.listener.(*net.TCPListener).File(); e == nil { - str := v.addr + "#" + gconv.String(f.Fd()) + "," - if v.isHttps { - m["https"] += str - } else { - m["http"] += str - } + str := v.addr + "#" + gconv.String(v.Fd()) + "," + if v.isHttps { + m["https"] += str } else { - glog.Errorfln("failed to get listener file: %v", e) + m["http"] += str } } + // 去掉末尾的","号 + if len(m["https"]) > 0 { + m["https"] = m["https"][0 : len(m["https"]) - 1] + } if len(m["http"]) > 0 { m["http"] = m["http"][0 : len(m["http"]) - 1] } - if len(m["https"]) > 0 { - m["https"] = m["https"][0 : len(m["https"]) - 1] - } + return m } diff --git a/g/net/ghttp/ghttp_server_comm_child.go b/g/net/ghttp/ghttp_server_comm_child.go index d0744ffd1..e1150576c 100644 --- a/g/net/ghttp/ghttp_server_comm_child.go +++ b/g/net/ghttp/ghttp_server_comm_child.go @@ -52,8 +52,12 @@ func onCommChildRestart(pid int, data []byte) { for _, item := range strings.Split(fdv, ",") { array := strings.Split(item, "#") fd := uintptr(gconv.Uint(array[1])) - s += fmt.Sprintf("%s#%d,", array[0], 3 + len(p.ExtraFiles)) - p.ExtraFiles = append(p.ExtraFiles, os.NewFile(fd, "")) + if fd > 0 { + s += fmt.Sprintf("%s#%d,", array[0], 3 + len(p.ExtraFiles)) + p.ExtraFiles = append(p.ExtraFiles, os.NewFile(fd, "")) + } else { + s += fmt.Sprintf("%s#%d,", array[0], 0) + } } sfm[name][fdk] = strings.TrimRight(s, ",") } @@ -75,7 +79,6 @@ func onCommChildShutdown(pid int, data []byte) { if runtime.GOOS != "windows" { shutdownWebServers() } - glog.Printfln("%d: shutdown done", gproc.Pid()) } // 更新上一次主进程主动与子进程通信的时间 @@ -94,13 +97,12 @@ func handleChildProcessHeartbeat() { // 子进程有时会无法退出(僵尸?),这里直接使用exit,而不是return //glog.Printfln("%d: %d - %d > %d", gproc.Pid(), int(gtime.Millisecond()), lastHeartbeatTime.Val(), gPROC_HEARTBEAT_TIMEOUT) //glog.Printfln("%d: heartbeat timeout, exit", gproc.Pid()) - glog.Printfln("%d: exit", gproc.Pid()) + glog.Printfln("%d: waiting %dms for shutdown timeout, exit", gproc.Pid(), gPROC_HEARTBEAT_TIMEOUT) os.Exit(0) } // 未开启心跳检测的闲置超过一定时间则主动关闭 if !checkHeartbeat.Val() && gproc.Uptime() > gPROC_CHILD_MAX_IDLE_TIME { - //glog.Printfln("%d: max idle time exceeded, exit", gproc.Pid()) - glog.Printfln("%d: exit", gproc.Pid()) + glog.Printfln("%d: max idle time %dms exceeded, exit", gproc.Pid(), gPROC_CHILD_MAX_IDLE_TIME) os.Exit(0) } } diff --git a/g/net/ghttp/ghttp_server_comm_signal_unix.go b/g/net/ghttp/ghttp_server_comm_signal_unix.go index 177ba6067..af56d9356 100644 --- a/g/net/ghttp/ghttp_server_comm_signal_unix.go +++ b/g/net/ghttp/ghttp_server_comm_signal_unix.go @@ -30,16 +30,18 @@ func handleProcessSignal() { for { sig = <- procSignalChan switch sig { - // 进程终止,停止所有子进程运行 - case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGHUP, syscall.SIGTERM: - sendProcessMsg(gproc.Pid(), gMSG_SHUTDOWN, nil) - return + // 进程终止,停止所有子进程运行 + case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGHUP, syscall.SIGTERM: + sendProcessMsg(gproc.Pid(), gMSG_SHUTDOWN, nil) + // 强制性kill掉所有子进程 + procManager.KillAll() + return // 用户信号,重启服务 - case syscall.SIGUSR1: - sendProcessMsg(gproc.Pid(), gMSG_RESTART, nil) + case syscall.SIGUSR1: + sendProcessMsg(gproc.Pid(), gMSG_RESTART, nil) - default: + default: } } } \ No newline at end of file diff --git a/g/net/ghttp/ghttp_server_graceful.go b/g/net/ghttp/ghttp_server_graceful.go index 6c1387f83..d6a6a9f94 100644 --- a/g/net/ghttp/ghttp_server_graceful.go +++ b/g/net/ghttp/ghttp_server_graceful.go @@ -71,10 +71,11 @@ func (s *gracefulServer) ListenAndServe() error { // 获得文件描述符 func (s *gracefulServer) Fd() uintptr { - file, err := s.listener.(*net.TCPListener).File() - //file, err := s.rawln.File() - if err == nil { - return file.Fd() + if s.listener != nil { + file, err := s.listener.(*net.TCPListener).File() + if err == nil { + return file.Fd() + } } return 0 } @@ -155,9 +156,9 @@ func (s *gracefulServer) getNetListener(addr string) (net.Listener, error) { // 执行请求优雅关闭 func (s *gracefulServer) shutdown() { if err := s.httpServer.Shutdown(context.Background()); err != nil { - glog.Errorfln("%d: %s server [%s] shutdown error: %v", gproc.Pid(), s.getProto(), s.addr, err) + //glog.Errorfln("%d: %s server [%s] shutdown error: %v", gproc.Pid(), s.getProto(), s.addr, err) } else { - glog.Printfln("%d: %s server [%s] shutdown smoothly", gproc.Pid(), s.getProto(), s.addr) + //glog.Printfln("%d: %s server [%s] shutdown smoothly", gproc.Pid(), s.getProto(), s.addr) s.shutdownChan <- true } } diff --git a/geg/net/ghttp/hot_restart/multi_port_and_server.go b/geg/net/ghttp/hot_restart/multi_port_and_server.go index b0c9cadad..536d35cd1 100644 --- a/geg/net/ghttp/hot_restart/multi_port_and_server.go +++ b/geg/net/ghttp/hot_restart/multi_port_and_server.go @@ -11,9 +11,10 @@ func main() { s1 := g.Server("s1") s1.EnableAdmin() s1.BindHandler("/", func(r *ghttp.Request) { - r.Response.Write("before time, pid:", gproc.Pid()) + pid := gproc.Pid() + r.Response.Writeln("before restart, pid:", pid) time.Sleep(10*time.Second) - r.Response.Write("after time, pid:", gproc.Pid()) + r.Response.Writeln("after restart, pid:", gproc.Pid()) }) s1.BindHandler("/pid", func(r *ghttp.Request) { r.Response.Write(gproc.Pid()) diff --git a/geg/net/ghttp/hot_restart/simple.go b/geg/net/ghttp/hot_restart/simple.go index c227c05ec..0129446a8 100644 --- a/geg/net/ghttp/hot_restart/simple.go +++ b/geg/net/ghttp/hot_restart/simple.go @@ -3,21 +3,21 @@ package main import ( "gitee.com/johng/gf/g" "gitee.com/johng/gf/g/net/ghttp" + "gitee.com/johng/gf/g/os/gproc" + "time" ) func main() { s := g.Server() - s.BindHandler("/", func(r *ghttp.Request){ - r.Response.Writeln("hello") + s.BindHandler("/sleep", func(r *ghttp.Request){ + r.Response.Writeln(gproc.Pid()) + time.Sleep(10*time.Second) + r.Response.Writeln(gproc.Pid()) }) - s.BindHandler("/restart", func(r *ghttp.Request){ - r.Response.Writeln("restart server") - r.Server.Restart() - }) - s.BindHandler("/shutdown", func(r *ghttp.Request){ - r.Response.Writeln("shutdown server") - r.Server.Shutdown() + s.BindHandler("/pid", func(r *ghttp.Request){ + r.Response.Writeln(gproc.Pid()) }) + s.EnableAdmin() s.SetPort(8199) s.Run() } \ No newline at end of file