mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
改进ghttp.Server退出机制处理
This commit is contained in:
@ -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返回
|
||||
|
||||
@ -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服务
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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的作用除了校验地址正确性以外,还转换分隔符号为当前系统正确的文件分隔符号
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user