mirror of
https://gitee.com/johng/gf
synced 2026-06-07 10:22:11 +08:00
完成ghttp.Server热重启特性的HTTP&HTTPS在Linux下的功能及稳定性测试
This commit is contained in:
@ -127,7 +127,11 @@ func init() {
|
||||
doneChan <- struct{}{}
|
||||
|
||||
if !gproc.IsChild() {
|
||||
glog.Printfln("%d: all web server shutdown smoothly", gproc.Pid())
|
||||
if serverMapping.Size() > 1 {
|
||||
glog.Printfln("%d: all web servers shutdown", gproc.Pid())
|
||||
} else {
|
||||
glog.Printfln("%d: web server shutdown", gproc.Pid())
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
@ -262,6 +266,7 @@ func (s *Server) startServer(fdMap listenerFdMap) {
|
||||
} else {
|
||||
s.servers = append(s.servers, s.newGracefulServer(addr))
|
||||
}
|
||||
s.servers[len(s.servers) - 1].isHttps = true
|
||||
}
|
||||
}
|
||||
// ================
|
||||
|
||||
@ -59,6 +59,7 @@ func onCommMainNewFork(pid int, data []byte) {
|
||||
|
||||
// 关闭服务,通知所有子进程退出(Kill强制性退出)
|
||||
func onCommMainShutdown(pid int, data []byte) {
|
||||
procManager.Send(formatMsgBuffer(gMSG_CLOSE, nil))
|
||||
procManager.KillAll()
|
||||
procManager.WaitAll()
|
||||
}
|
||||
@ -83,7 +84,7 @@ func handleMainProcessHeartbeat() {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果所有子进程都退出,并且主进程未活动达到超时时间,那么主进程也没存在的必要
|
||||
// (双保险)如果所有子进程都退出,并且主进程未活动达到超时时间,那么主进程也没存在的必要
|
||||
if procManager.Size() == 0 && int(gtime.Millisecond()) - lastUpdateTime.Val() > gPROC_HEARTBEAT_TIMEOUT{
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
@ -34,6 +34,9 @@ func handleProcessSignal() {
|
||||
// 进程终止,停止所有子进程运行
|
||||
case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGHUP, syscall.SIGTERM:
|
||||
sendProcessMsg(gproc.Pid(), gMSG_SHUTDOWN, nil)
|
||||
if gproc.IsChild() {
|
||||
sendProcessMsg(gproc.PPid(), gMSG_SHUTDOWN, nil)
|
||||
}
|
||||
return
|
||||
|
||||
// 用户信号,热重启服务
|
||||
|
||||
@ -7,19 +7,14 @@
|
||||
package ghttp
|
||||
|
||||
import (
|
||||
"os"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"context"
|
||||
"net/http"
|
||||
"crypto/tls"
|
||||
"gitee.com/johng/gf/g/os/glog"
|
||||
"gitee.com/johng/gf/g/os/gproc"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
gGRACEFUL_SHUTDOWN_TIMEOUT = 10*time.Second // 优雅关闭链接时的超时时间
|
||||
)
|
||||
|
||||
// 优雅的Web Server对象封装
|
||||
@ -27,8 +22,8 @@ type gracefulServer struct {
|
||||
fd uintptr
|
||||
addr string
|
||||
httpServer *http.Server
|
||||
rawln *net.TCPListener // 原始listener
|
||||
listener net.Listener // 接口化封装的listener
|
||||
rawListener net.Listener // 原始listener
|
||||
listener net.Listener // 接口化封装的listener
|
||||
isHttps bool
|
||||
shutdownChan chan bool
|
||||
}
|
||||
@ -40,6 +35,7 @@ func (s *Server) newGracefulServer(addr string, fd...int) *gracefulServer {
|
||||
httpServer : s.newHttpServer(addr),
|
||||
shutdownChan : make(chan bool),
|
||||
}
|
||||
// 是否有继承的文件描述符
|
||||
if len(fd) > 0 && fd[0] > 0 {
|
||||
gs.fd = uintptr(fd[0])
|
||||
}
|
||||
@ -65,19 +61,15 @@ func (s *gracefulServer) ListenAndServe() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//file, err := ln.(*net.TCPListener).File()
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
//s.fd = file.Fd()
|
||||
s.listener = ln
|
||||
s.listener = ln
|
||||
s.rawListener = ln
|
||||
return s.doServe()
|
||||
}
|
||||
|
||||
// 获得文件描述符
|
||||
func (s *gracefulServer) Fd() uintptr {
|
||||
if s.listener != nil {
|
||||
file, err := s.listener.(*net.TCPListener).File()
|
||||
if s.rawListener != nil {
|
||||
file, err := s.rawListener.(*net.TCPListener).File()
|
||||
if err == nil {
|
||||
return file.Fd()
|
||||
}
|
||||
@ -110,13 +102,9 @@ func (s *gracefulServer) ListenAndServeTLS(certFile, keyFile string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//file, err := ln.(*net.TCPListener).File()
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
//s.fd = file.Fd()
|
||||
s.listener = tls.NewListener(ln, config)
|
||||
s.isHttps = true
|
||||
|
||||
s.listener = tls.NewListener(ln, config)
|
||||
s.rawListener = ln
|
||||
return s.doServe()
|
||||
}
|
||||
|
||||
@ -131,7 +119,11 @@ func (s *gracefulServer) getProto() string {
|
||||
|
||||
// 开始执行Web Server服务处理
|
||||
func (s *gracefulServer) doServe() error {
|
||||
glog.Printfln("%d: %s server started listening on [%s]", gproc.Pid(), s.getProto(), s.addr)
|
||||
action := "started"
|
||||
if s.fd != 0 {
|
||||
action = "reloaded"
|
||||
}
|
||||
glog.Printfln("%d: %s server %s listening on [%s]", gproc.Pid(), s.getProto(), action, s.addr)
|
||||
err := s.httpServer.Serve(s.listener)
|
||||
<-s.shutdownChan
|
||||
return err
|
||||
|
||||
@ -31,14 +31,17 @@ func Pid() int {
|
||||
return os.Getpid()
|
||||
}
|
||||
|
||||
// 获取父进程ID(gproc父进程,不存在时则使用系统父进程)
|
||||
// 获取父进程ID(gproc父进程,如果当前进程本身就是父进程,那么返回自身的pid,不存在时则使用系统父进程)
|
||||
func PPid() int {
|
||||
if !IsChild() {
|
||||
return Pid()
|
||||
}
|
||||
// gPROC_ENV_KEY_PPID_KEY为gproc包自定义的父进程
|
||||
ppidValue := os.Getenv(gPROC_ENV_KEY_PPID_KEY)
|
||||
if ppidValue != "" {
|
||||
return gconv.Int(ppidValue)
|
||||
}
|
||||
return os.Getppid()
|
||||
return PPidOS()
|
||||
}
|
||||
|
||||
// 获取父进程ID(系统父进程)
|
||||
|
||||
@ -11,7 +11,8 @@ func main() {
|
||||
r.Response.Writeln("您可以同时通过HTTP和HTTPS方式看到该内容!")
|
||||
})
|
||||
s.EnableHTTPS("/home/john/temp/server.crt", "/home/john/temp/server.key")
|
||||
s.SetHTTPSPort(8198)
|
||||
s.SetPort(8199)
|
||||
s.SetHTTPSPort(8198, 8199)
|
||||
s.SetPort(8200, 8300)
|
||||
s.EnableAdmin()
|
||||
s.Run()
|
||||
}
|
||||
18
geg/net/ghttp/reload/https_http.go
Normal file
18
geg/net/ghttp/reload/https_http.go
Normal file
@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"gitee.com/johng/gf/g/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := ghttp.GetServer()
|
||||
s.EnableAdmin()
|
||||
s.BindHandler("/", func(r *ghttp.Request){
|
||||
r.Response.Writeln("您可以同时通过HTTP和HTTPS方式看到该内容!")
|
||||
})
|
||||
s.EnableHTTPS("/home/john/temp/server.crt", "/home/john/temp/server.key")
|
||||
s.SetHTTPSPort(8198, 8199)
|
||||
s.SetPort(8200, 8300)
|
||||
s.EnableAdmin()
|
||||
s.Run()
|
||||
}
|
||||
Reference in New Issue
Block a user