From 2a7ea92c2eda5149bb355bcc99b6258189077821 Mon Sep 17 00:00:00 2001 From: john Date: Wed, 1 Aug 2018 13:04:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E8=BF=9Bghttp.Server=E9=80=80?= =?UTF-8?q?=E5=87=BA=E6=9C=BA=E5=88=B6=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- g/net/ghttp/ghttp_server.go | 28 ++++++++++++++---- g/net/ghttp/ghttp_server_admin.go | 32 ++++++++++++++------- g/net/ghttp/ghttp_server_admin_unix.go | 4 +-- g/net/ghttp/ghttp_server_graceful.go | 20 ++++++------- g/net/ghttp/ghttp_server_options.go | 28 +++++++++--------- g/net/ghttp/ghttp_server_router.go | 2 +- g/net/ghttp/ghttp_server_service_handler.go | 8 +++--- 7 files changed, 75 insertions(+), 47 deletions(-) diff --git a/g/net/ghttp/ghttp_server.go b/g/net/ghttp/ghttp_server.go index b95b352ff..1541ba9c2 100644 --- a/g/net/ghttp/ghttp_server.go +++ b/g/net/ghttp/ghttp_server.go @@ -30,6 +30,10 @@ import ( "container/list" ) +const ( + SERVER_STATUS_STOPPED = 0 // Server状态:停止 + SERVER_STATUS_RUNNING = 1 // Server状态:运行 +) const ( gHTTP_METHODS = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE" gDEFAULT_SERVER = "default" @@ -39,8 +43,6 @@ const ( gDEFAULT_COOKIE_MAX_AGE = 86400*365 // 默认cookie有效期(一年) gDEFAULT_SESSION_MAX_AGE = 600 // 默认session有效期(600秒) gDEFAULT_SESSION_ID_NAME = "gfsessionid" // 默认存放Cookie中的SessionId名称 - gSERVER_STATUS_STOPPED = 0 // Server状态:停止 - gSERVER_STATUS_RUNNING = 1 // Server状态:运行 ) // ghttp.Server结构体 @@ -49,7 +51,6 @@ type Server struct { name string // 服务名称,方便识别 paths *gspath.SPath // 静态文件检索对象 config ServerConfig // 配置对象 - status int8 // 当前服务器状态(0:未启动,1:运行中) servers []*gracefulServer // 底层http.Server列表 methodsMap map[string]bool // 所有支持的HTTP Method(初始化时自动填充) servedCount *gtype.Int // 已经服务的请求数(4-8字节,不考虑溢出情况),同时作为请求ID @@ -120,6 +121,9 @@ type listenerFdMap map[string]string // Server表,用以存储和检索名称与Server对象之间的关联关系 var serverMapping = gmap.NewStringInterfaceMap() +// 正常运行的Server数量,如果没有运行、失败或者全部退出,那么该值为0 +var serverRunning = gtype.NewInt() + // Web Socket默认配置 var wsUpgrader = websocket.Upgrader{} @@ -214,7 +218,7 @@ func (s *Server) Start() error { } } - if s.status == gSERVER_STATUS_RUNNING { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server is already running") } // 底层http server配置 @@ -351,20 +355,32 @@ func (s *Server) startServer(fdMap listenerFdMap) { // 开始执行异步监听 for _, v := range s.servers { go func(server *gracefulServer) { - var err error + serverRunning.Add(1) + err := (error)(nil) if server.isHttps { err = server.ListenAndServeTLS(s.config.HTTPSCertPath, s.config.HTTPSKeyPath) } else { err = server.ListenAndServe() } + serverRunning.Add(-1) // 如果非关闭错误,那么提示报错,否则认为是正常的服务关闭操作 if err != nil && !strings.EqualFold(http.ErrServerClosed.Error(), err.Error()) { glog.Error(err) } + // 如果所有异步的Server都已经停止,那么主Server就可以退出了 + if serverRunning.Val() < 1 { + doneChan <- struct{}{} + } }(v) } +} - s.status = gSERVER_STATUS_RUNNING +// 获取当前服务器的状态 +func (s *Server) Status() int { + if serverRunning.Val() > 0 { + return SERVER_STATUS_RUNNING + } + return SERVER_STATUS_STOPPED } // 获取当前监听的文件描述符信息,构造成map返回 diff --git a/g/net/ghttp/ghttp_server_admin.go b/g/net/ghttp/ghttp_server_admin.go index abce91fc1..e62d1c0e7 100644 --- a/g/net/ghttp/ghttp_server_admin.go +++ b/g/net/ghttp/ghttp_server_admin.go @@ -112,7 +112,7 @@ func (s *Server) Restart(newExeFilePath...string) error { if err := s.checkActionFrequence(); err != nil { return err } - restartWebServers(newExeFilePath...) + restartWebServers(false, newExeFilePath...) return nil } @@ -126,7 +126,7 @@ func (s *Server) Shutdown() error { if err := s.checkActionFrequence(); err != nil { return err } - shutdownWebServers() + shutdownWebServers(false) return nil } @@ -231,29 +231,41 @@ func bufferToServerFdMap(buffer []byte) map[string]listenerFdMap { } // Web Server重启 -func restartWebServers(newExeFilePath...string) { +func restartWebServers(isSignal bool, newExeFilePath...string) { serverProcessStatus.Set(gADMIN_ACTION_RESTARTING) glog.Printfln("%d: server restarting", gproc.Pid()) if runtime.GOOS == "windows" { - // 异步1秒后再执行重启,目的是让接口能够正确返回结果,否则接口会报错(因为web server关闭了) - gtime.SetTimeout(time.Second, func() { + if isSignal { + // 在终端信号下,立即执行重启操作 forcedlyCloseWebServers() forkRestartProcess(newExeFilePath...) - }) + } else { + // 非终端信号下,异步1秒后再执行重启,目的是让接口能够正确返回结果,否则接口会报错(因为web server关闭了) + gtime.SetTimeout(time.Second, func() { + forcedlyCloseWebServers() + forkRestartProcess(newExeFilePath...) + }) + } } else { forkReloadProcess(newExeFilePath...) } } // Web Server关闭服务 -func shutdownWebServers() { +func shutdownWebServers(isSignal bool) { serverProcessStatus.Set(gADMIN_ACTION_SHUTINGDOWN) glog.Printfln("%d: server shutting down", gproc.Pid()) - // 异步1秒后再执行重启,目的是让接口能够正确返回结果,否则接口会报错(因为web server关闭了) - gtime.SetTimeout(time.Second, func() { + if isSignal { + // 在终端信号下,立即执行关闭操作 forcedlyCloseWebServers() doneChan <- struct{}{} - }) + } else { + // 非终端信号下,异步1秒后再执行关闭,目的是让接口能够正确返回结果,否则接口会报错(因为web server关闭了) + gtime.SetTimeout(time.Second, func() { + forcedlyCloseWebServers() + doneChan <- struct{}{} + }) + } } // 关优雅闭进程所有端口的Web Server服务 diff --git a/g/net/ghttp/ghttp_server_admin_unix.go b/g/net/ghttp/ghttp_server_admin_unix.go index 647374f73..187e04a7d 100644 --- a/g/net/ghttp/ghttp_server_admin_unix.go +++ b/g/net/ghttp/ghttp_server_admin_unix.go @@ -35,12 +35,12 @@ func handleProcessSignal() { switch sig { // 进程终止,停止所有子进程运行 case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGHUP, syscall.SIGTERM: - shutdownWebServers() + shutdownWebServers(true) return // 用户信号,重启服务 case syscall.SIGUSR1: - restartWebServers() + restartWebServers(true) return default: diff --git a/g/net/ghttp/ghttp_server_graceful.go b/g/net/ghttp/ghttp_server_graceful.go index f406e24fe..05017ab32 100644 --- a/g/net/ghttp/ghttp_server_graceful.go +++ b/g/net/ghttp/ghttp_server_graceful.go @@ -25,8 +25,8 @@ type gracefulServer struct { httpServer *http.Server rawListener net.Listener // 原始listener listener net.Listener // 接口化封装的listener - isHttps bool - shutdownChan chan bool + isHttps bool // 是否HTTPS + status int // 当前Server状态(关闭/运行) } // 创建一个优雅的Http Server @@ -34,7 +34,6 @@ func (s *Server) newGracefulServer(addr string, fd...int) *gracefulServer { gs := &gracefulServer { addr : addr, httpServer : s.newHttpServer(addr), - shutdownChan : make(chan bool), } // 是否有继承的文件描述符 if len(fd) > 0 && fd[0] > 0 { @@ -125,8 +124,9 @@ func (s *gracefulServer) doServe() error { action = "reloaded" } glog.Printfln("%d: %s server %s listening on [%s]", gproc.Pid(), s.getProto(), action, s.addr) + s.status = SERVER_STATUS_RUNNING err := s.httpServer.Serve(s.listener) - <-s.shutdownChan + s.status = SERVER_STATUS_STOPPED return err } @@ -162,21 +162,21 @@ func (s *gracefulServer) getNetListener(addr string) (net.Listener, error) { // 执行请求优雅关闭 func (s *gracefulServer) shutdown() { + if s.status == SERVER_STATUS_STOPPED { + return + } 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) - } else { - //glog.Printfln("%d: %s server [%s] shutdown smoothly", gproc.Pid(), s.getProto(), s.addr) - s.shutdownChan <- true } } // 执行请求强制关闭 func (s *gracefulServer) close() { + if s.status == SERVER_STATUS_STOPPED { + return + } if err := s.httpServer.Close(); err != nil { glog.Errorfln("%d: %s server [%s] closed error: %v", gproc.Pid(), s.getProto(), s.addr, err) - } else { - //glog.Printfln("%d: %s server [%s] closed smoothly", gproc.Pid(), s.getProto(), s.addr) - s.shutdownChan <- true } } diff --git a/g/net/ghttp/ghttp_server_options.go b/g/net/ghttp/ghttp_server_options.go index 8e3d96d6a..946f7089e 100644 --- a/g/net/ghttp/ghttp_server_options.go +++ b/g/net/ghttp/ghttp_server_options.go @@ -19,7 +19,7 @@ import ( // http server setting设置 // 注意使用该方法进行http server配置时,需要配置所有的配置项,否则没有配置的属性将会默认变量为空 func (s *Server)SetConfig(c ServerConfig) error { - if s.status == 1 { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server config cannot be changed while running") } if c.Handler == nil { @@ -42,7 +42,7 @@ func (s *Server)SetConfig(c ServerConfig) error { // 设置http server参数 - Addr func (s *Server)SetAddr(addr string) error { - if s.status == 1 { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server config cannot be changed while running") } s.config.Addr = addr @@ -51,7 +51,7 @@ func (s *Server)SetAddr(addr string) error { // 设置http server参数 - Port func (s *Server)SetPort(port...int) error { - if s.status == 1 { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server config cannot be changed while running") } if len(port) > 0 { @@ -68,7 +68,7 @@ func (s *Server)SetPort(port...int) error { // 设置http server参数 - HTTPS Addr func (s *Server)SetHTTPSAddr(addr string) error { - if s.status == 1 { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server config cannot be changed while running") } s.config.HTTPSAddr = addr @@ -77,7 +77,7 @@ func (s *Server)SetHTTPSAddr(addr string) error { // 设置http server参数 - HTTPS Port func (s *Server)SetHTTPSPort(port...int) error { - if s.status == 1 { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server config cannot be changed while running") } if len(port) > 0 { @@ -94,7 +94,7 @@ func (s *Server)SetHTTPSPort(port...int) error { // 开启HTTPS支持,但是必须提供Cert和Key文件 func (s *Server)EnableHTTPS(certFile, keyFile string) error { - if s.status == 1 { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server config cannot be changed while running") } s.config.HTTPSCertPath = certFile @@ -104,7 +104,7 @@ func (s *Server)EnableHTTPS(certFile, keyFile string) error { // 设置http server参数 - ReadTimeout func (s *Server)SetReadTimeout(t time.Duration) error { - if s.status == 1 { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server config cannot be changed while running") } s.config.ReadTimeout = t @@ -113,7 +113,7 @@ func (s *Server)SetReadTimeout(t time.Duration) error { // 设置http server参数 - WriteTimeout func (s *Server)SetWriteTimeout(t time.Duration) error { - if s.status == 1 { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server config cannot be changed while running") } s.config.WriteTimeout = t @@ -122,7 +122,7 @@ func (s *Server)SetWriteTimeout(t time.Duration) error { // 设置http server参数 - IdleTimeout func (s *Server)SetIdleTimeout(t time.Duration) error { - if s.status == 1 { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server config cannot be changed while running") } s.config.IdleTimeout = t @@ -131,7 +131,7 @@ func (s *Server)SetIdleTimeout(t time.Duration) error { // 设置http server参数 - MaxHeaderBytes func (s *Server)SetMaxHeaderBytes(b int) error { - if s.status == 1 { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server config cannot be changed while running") } s.config.MaxHeaderBytes = b @@ -140,7 +140,7 @@ func (s *Server)SetMaxHeaderBytes(b int) error { // 设置http server参数 - IndexFiles,默认展示文件,如:index.html, index.htm func (s *Server)SetIndexFiles(index []string) error { - if s.status == 1 { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server config cannot be changed while running") } s.config.IndexFiles = index @@ -149,7 +149,7 @@ func (s *Server)SetIndexFiles(index []string) error { // 允许展示访问目录的文件列表 func (s *Server)SetIndexFolder(index bool) error { - if s.status == 1 { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server config cannot be changed while running") } s.config.IndexFolder = index @@ -158,7 +158,7 @@ func (s *Server)SetIndexFolder(index bool) error { // 设置http server参数 - ServerAgent func (s *Server)SetServerAgent(agent string) error { - if s.status == 1 { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server config cannot be changed while running") } s.config.ServerAgent = agent @@ -167,7 +167,7 @@ func (s *Server)SetServerAgent(agent string) error { // 设置http server参数 - ServerRoot func (s *Server)SetServerRoot(root string) error { - if s.status == 1 { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server config cannot be changed while running") } // RealPath的作用除了校验地址正确性以外,还转换分隔符号为当前系统正确的文件分隔符号 diff --git a/g/net/ghttp/ghttp_server_router.go b/g/net/ghttp/ghttp_server_router.go index d37da35a1..ece3cc59f 100644 --- a/g/net/ghttp/ghttp_server_router.go +++ b/g/net/ghttp/ghttp_server_router.go @@ -69,7 +69,7 @@ func (s *Server)parsePattern(pattern string) (domain, method, uri string, err er // 如果带有hook参数,表示是回调注册方法,否则为普通路由执行方法。 func (s *Server) setHandler(pattern string, handler *handlerItem, hook ... string) error { // Web Server正字运行时无法动态注册路由方法 - if s.status == gSERVER_STATUS_RUNNING { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("cannnot bind handler while server running") } var hookName string diff --git a/g/net/ghttp/ghttp_server_service_handler.go b/g/net/ghttp/ghttp_server_service_handler.go index f35f8ce1e..b50ac1f37 100644 --- a/g/net/ghttp/ghttp_server_service_handler.go +++ b/g/net/ghttp/ghttp_server_service_handler.go @@ -14,7 +14,7 @@ import ( ) // 注意该方法是直接绑定函数的内存地址,执行的时候直接执行该方法,不会存在初始化新的控制器逻辑 -func (s *Server)BindHandler(pattern string, handler HandlerFunc) error { +func (s *Server) BindHandler(pattern string, handler HandlerFunc) error { return s.bindHandlerItem(pattern, &handlerItem{ ctype : nil, fname : "", @@ -25,15 +25,15 @@ func (s *Server)BindHandler(pattern string, handler HandlerFunc) error { // 绑定URI到操作函数/方法 // pattern的格式形如:/user/list, put:/user, delete:/user, post:/user@johng.cn // 支持RESTful的请求格式,具体业务逻辑由绑定的处理方法来执行 -func (s *Server)bindHandlerItem(pattern string, item *handlerItem) error { - if s.status == 1 { +func (s *Server) bindHandlerItem(pattern string, item *handlerItem) error { + if s.Status() == SERVER_STATUS_RUNNING { return errors.New("server handlers cannot be changed while running") } return s.setHandler(pattern, item) } // 通过映射数组绑定URI到操作函数/方法 -func (s *Server)bindHandlerByMap(m handlerMap) error { +func (s *Server) bindHandlerByMap(m handlerMap) error { for p, h := range m { if err := s.bindHandlerItem(p, h); err != nil { return err