gf/net/ghttp/ghttp_server_graceful.go

190 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2018 gf Author(https://github.com/gogf/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://github.com/gogf/gf.
package ghttp
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"
"os"
"time"
"github.com/gogf/gf/os/glog"
"github.com/gogf/gf/os/gproc"
)
// 优雅的Web Server对象封装
type gracefulServer struct {
fd uintptr // 热重启时传递的socket监听文件句柄
itemFunc string // 监听地址信息
httpServer *http.Server // 底层http.Server
rawListener net.Listener // 原始listener
listener net.Listener // 接口化封装的listener
isHttps bool // 是否HTTPS
status int // 当前Server状态(关闭/运行)
}
// 创建一个优雅的Http Server
func (s *Server) newGracefulServer(itemFunc string, fd ...int) *gracefulServer {
gs := &gracefulServer{
itemFunc: itemFunc,
httpServer: s.newHttpServer(itemFunc),
}
// 是否有继承的文件描述符
if len(fd) > 0 && fd[0] > 0 {
gs.fd = uintptr(fd[0])
}
return gs
}
// 生成一个底层的Web Server对象
func (s *Server) newHttpServer(itemFunc string) *http.Server {
server := &http.Server{
Addr: itemFunc,
Handler: s.config.Handler,
ReadTimeout: s.config.ReadTimeout,
WriteTimeout: s.config.WriteTimeout,
IdleTimeout: s.config.IdleTimeout,
MaxHeaderBytes: s.config.MaxHeaderBytes,
}
server.SetKeepAlivesEnabled(s.config.KeepAlive)
return server
}
// 执行HTTP监听
func (s *gracefulServer) ListenAndServe() error {
itemFunc := s.httpServer.Addr
ln, err := s.getNetListener(itemFunc)
if err != nil {
return err
}
s.listener = ln
s.rawListener = ln
return s.doServe()
}
// 获得文件描述符
func (s *gracefulServer) Fd() uintptr {
if s.rawListener != nil {
file, err := s.rawListener.(*net.TCPListener).File()
if err == nil {
return file.Fd()
}
}
return 0
}
// 设置自定义fd
func (s *gracefulServer) setFd(fd int) {
s.fd = uintptr(fd)
}
// 执行HTTPS监听
func (s *gracefulServer) ListenAndServeTLS(certFile, keyFile string, tlsConfig ...*tls.Config) error {
itemFunc := s.httpServer.Addr
config := (*tls.Config)(nil)
if len(tlsConfig) > 0 {
config = tlsConfig[0]
} else if s.httpServer.TLSConfig != nil {
*config = *s.httpServer.TLSConfig
}
if config.NextProtos == nil {
config.NextProtos = []string{"http/1.1"}
}
err := error(nil)
if len(config.Certificates) == 0 {
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(itemFunc)
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.Printf("%d: %s server %s listening on [%s]", gproc.Pid(), s.getProto(), action, s.itemFunc)
s.status = SERVER_STATUS_RUNNING
err := s.httpServer.Serve(s.listener)
s.status = SERVER_STATUS_STOPPED
return err
}
// 自定义的net.Listener
func (s *gracefulServer) getNetListener(itemFunc string) (net.Listener, error) {
var ln net.Listener
var err error
if s.fd > 0 {
f := os.NewFile(s.fd, "")
ln, err = net.FileListener(f)
if err != nil {
err = fmt.Errorf("%d: net.FileListener error: %v", gproc.Pid(), err)
return nil, err
}
} else {
// 如果监听失败1秒后重试最多重试3次
for i := 0; i < 3; i++ {
ln, err = net.Listen("tcp", itemFunc)
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() {
if s.status == SERVER_STATUS_STOPPED {
return
}
if err := s.httpServer.Shutdown(context.Background()); err != nil {
glog.Errorf("%d: %s server [%s] shutdown error: %v", gproc.Pid(), s.getProto(), s.itemFunc, err)
}
}
// 执行请求强制关闭
func (s *gracefulServer) close() {
if s.status == SERVER_STATUS_STOPPED {
return
}
if err := s.httpServer.Close(); err != nil {
glog.Errorf("%d: %s server [%s] closed error: %v", gproc.Pid(), s.getProto(), s.itemFunc, err)
}
}