gf/g/net/ghttp/ghttp_server_graceful.go

185 lines
4.9 KiB
Go
Raw Normal View History

// Copyright 2018 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
package ghttp
import (
"context"
"crypto/tls"
"errors"
"fmt"
2019-01-27 16:40:16 +08:00
"gitee.com/johng/gf/g/net/greuseport"
"gitee.com/johng/gf/g/os/glog"
"gitee.com/johng/gf/g/os/gproc"
"net"
"net/http"
"os"
"time"
)
// 优雅的Web Server对象封装
type gracefulServer struct {
2018-05-08 18:41:29 +08:00
fd uintptr
addr string
httpServer *http.Server
rawListener net.Listener // 原始listener
listener net.Listener // 接口化封装的listener
2018-08-01 13:04:15 +08:00
isHttps bool // 是否HTTPS
status int // 当前Server状态(关闭/运行)
}
// 创建一个优雅的Http Server
2018-05-08 18:41:29 +08:00
func (s *Server) newGracefulServer(addr string, fd...int) *gracefulServer {
gs := &gracefulServer {
addr : addr,
httpServer : s.newHttpServer(addr),
}
// 是否有继承的文件描述符
2018-05-08 18:41:29 +08:00
if len(fd) > 0 && fd[0] > 0 {
gs.fd = uintptr(fd[0])
}
return gs
}
// 生成一个底层的Web Server对象
func (s *Server) newHttpServer(addr string) *http.Server {
return &http.Server {
Addr : addr,
Handler : s.config.Handler,
ReadTimeout : s.config.ReadTimeout,
WriteTimeout : s.config.WriteTimeout,
IdleTimeout : s.config.IdleTimeout,
MaxHeaderBytes : s.config.MaxHeaderBytes,
}
}
// 执行HTTP监听
func (s *gracefulServer) ListenAndServe() error {
addr := s.httpServer.Addr
ln, err := s.getNetListener(addr)
if err != nil {
return err
}
s.listener = ln
s.rawListener = ln
return s.doServe()
}
2018-05-13 22:00:10 +08:00
// 获得文件描述符
func (s *gracefulServer) Fd() uintptr {
if s.rawListener != nil {
file, err := s.rawListener.(*net.TCPListener).File()
if err == nil {
return file.Fd()
}
2018-05-13 22:00:10 +08:00
}
return 0
}
2018-05-10 19:16:41 +08:00
// 设置自定义fd
func (s *gracefulServer) setFd(fd int) {
s.fd = uintptr(fd)
}
// 执行HTTPS监听
func (s *gracefulServer) ListenAndServeTLS(certFile, keyFile string) error {
addr := s.httpServer.Addr
config := &tls.Config{}
if s.httpServer.TLSConfig != nil {
*config = *s.httpServer.TLSConfig
}
if config.NextProtos == nil {
config.NextProtos = []string{"http/1.1"}
}
err := error(nil)
config.Certificates = make([]tls.Certificate, 1)
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return errors.New(fmt.Sprintf(`open cert file "%s","%s" failed: %s`, certFile, keyFile, err.Error()))
}
ln, err := s.getNetListener(addr)
if err != nil {
return err
}
s.listener = tls.NewListener(ln, config)
s.rawListener = ln
return s.doServe()
}
// 获取服务协议字符串
func (s *gracefulServer) getProto() string {
proto := "http"
if s.isHttps {
proto = "https"
}
return proto
}
// 开始执行Web Server服务处理
func (s *gracefulServer) doServe() error {
action := "started"
if s.fd != 0 {
action = "reloaded"
}
glog.Printfln("%d: %s server %s listening on [%s]", gproc.Pid(), s.getProto(), action, s.addr)
2018-08-01 13:04:15 +08:00
s.status = SERVER_STATUS_RUNNING
err := s.httpServer.Serve(s.listener)
2018-08-01 13:04:15 +08:00
s.status = SERVER_STATUS_STOPPED
return err
}
// 自定义的net.Listener
func (s *gracefulServer) getNetListener(addr string) (net.Listener, error) {
var ln net.Listener
var err error
2018-05-08 18:41:29 +08:00
if s.fd > 0 {
f := os.NewFile(s.fd, "")
ln, err = net.FileListener(f)
if err != nil {
2018-05-11 23:17:25 +08:00
err = fmt.Errorf("%d: net.FileListener error: %v", gproc.Pid(), err)
return nil, err
}
} else {
// 如果监听失败1秒后重试最多重试3次
for i := 0; i < 3; i++ {
2019-01-27 16:40:16 +08:00
ln, err = greuseport.Listen("tcp", addr)
if err != nil {
err = fmt.Errorf("%d: net.Listen error: %v", gproc.Pid(), err)
time.Sleep(time.Second)
} else {
err = nil
break
}
}
if err != nil {
return nil, err
}
}
return ln, nil
}
// 执行请求优雅关闭
func (s *gracefulServer) shutdown() {
2018-08-01 13:04:15 +08:00
if s.status == SERVER_STATUS_STOPPED {
return
}
if err := s.httpServer.Shutdown(context.Background()); err != nil {
2018-05-15 15:09:41 +08:00
glog.Errorfln("%d: %s server [%s] shutdown error: %v", gproc.Pid(), s.getProto(), s.addr, err)
}
}
// 执行请求强制关闭
func (s *gracefulServer) close() {
2018-08-01 13:04:15 +08:00
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)
}
}