ghttp_server_graceful.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package ghttp
  7. import (
  8. "context"
  9. "crypto/tls"
  10. "fmt"
  11. "github.com/gogf/gf/errors/gcode"
  12. "github.com/gogf/gf/errors/gerror"
  13. "github.com/gogf/gf/os/gproc"
  14. "github.com/gogf/gf/os/gres"
  15. "github.com/gogf/gf/text/gstr"
  16. "log"
  17. "net"
  18. "net/http"
  19. "os"
  20. )
  21. // gracefulServer wraps the net/http.Server with graceful reload/restart feature.
  22. type gracefulServer struct {
  23. server *Server // Belonged server.
  24. fd uintptr // File descriptor for passing to child process when graceful reload.
  25. address string // Listening address like:":80", ":8080".
  26. httpServer *http.Server // Underlying http.Server.
  27. rawListener net.Listener // Underlying net.Listener.
  28. listener net.Listener // Wrapped net.Listener.
  29. isHttps bool // Is HTTPS.
  30. status int // Status of current server.
  31. }
  32. // newGracefulServer creates and returns a graceful http server with given address.
  33. // The optional parameter <fd> specifies the file descriptor which is passed from parent server.
  34. func (s *Server) newGracefulServer(address string, fd ...int) *gracefulServer {
  35. // Change port to address like: 80 -> :80
  36. if gstr.IsNumeric(address) {
  37. address = ":" + address
  38. }
  39. gs := &gracefulServer{
  40. server: s,
  41. address: address,
  42. httpServer: s.newHttpServer(address),
  43. }
  44. if len(fd) > 0 && fd[0] > 0 {
  45. gs.fd = uintptr(fd[0])
  46. }
  47. return gs
  48. }
  49. // newGracefulServer creates and returns a underlying http.Server with given address.
  50. func (s *Server) newHttpServer(address string) *http.Server {
  51. server := &http.Server{
  52. Addr: address,
  53. Handler: s.config.Handler,
  54. ReadTimeout: s.config.ReadTimeout,
  55. WriteTimeout: s.config.WriteTimeout,
  56. IdleTimeout: s.config.IdleTimeout,
  57. MaxHeaderBytes: s.config.MaxHeaderBytes,
  58. ErrorLog: log.New(&errorLogger{logger: s.config.Logger}, "", 0),
  59. }
  60. server.SetKeepAlivesEnabled(s.config.KeepAlive)
  61. return server
  62. }
  63. // ListenAndServe starts listening on configured address.
  64. func (s *gracefulServer) ListenAndServe() error {
  65. ln, err := s.getNetListener()
  66. if err != nil {
  67. return err
  68. }
  69. s.listener = ln
  70. s.rawListener = ln
  71. return s.doServe()
  72. }
  73. // Fd retrieves and returns the file descriptor of current server.
  74. // It is available ony in *nix like operation systems like: linux, unix, darwin.
  75. func (s *gracefulServer) Fd() uintptr {
  76. if s.rawListener != nil {
  77. file, err := s.rawListener.(*net.TCPListener).File()
  78. if err == nil {
  79. return file.Fd()
  80. }
  81. }
  82. return 0
  83. }
  84. // setFd sets the file descriptor for current server.
  85. func (s *gracefulServer) setFd(fd int) {
  86. s.fd = uintptr(fd)
  87. }
  88. // ListenAndServeTLS starts listening on configured address with HTTPS.
  89. // The parameter <certFile> and <keyFile> specify the necessary certification and key files for HTTPS.
  90. // The optional parameter <tlsConfig> specifies the custom TLS configuration.
  91. func (s *gracefulServer) ListenAndServeTLS(certFile, keyFile string, tlsConfig ...*tls.Config) error {
  92. var config *tls.Config
  93. if len(tlsConfig) > 0 && tlsConfig[0] != nil {
  94. config = tlsConfig[0]
  95. } else if s.httpServer.TLSConfig != nil {
  96. config = s.httpServer.TLSConfig
  97. } else {
  98. config = &tls.Config{}
  99. }
  100. if config.NextProtos == nil {
  101. config.NextProtos = []string{"http/1.1"}
  102. }
  103. err := error(nil)
  104. if len(config.Certificates) == 0 {
  105. config.Certificates = make([]tls.Certificate, 1)
  106. if gres.Contains(certFile) {
  107. config.Certificates[0], err = tls.X509KeyPair(
  108. gres.GetContent(certFile),
  109. gres.GetContent(keyFile),
  110. )
  111. } else {
  112. config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
  113. }
  114. }
  115. if err != nil {
  116. return gerror.WrapCodef(gcode.CodeInternalError, err, `open cert file "%s","%s" failed`, certFile, keyFile)
  117. }
  118. ln, err := s.getNetListener()
  119. if err != nil {
  120. return err
  121. }
  122. s.listener = tls.NewListener(ln, config)
  123. s.rawListener = ln
  124. return s.doServe()
  125. }
  126. // getProto retrieves and returns the proto string of current server.
  127. func (s *gracefulServer) getProto() string {
  128. proto := "http"
  129. if s.isHttps {
  130. proto = "https"
  131. }
  132. return proto
  133. }
  134. // doServe does staring the serving.
  135. func (s *gracefulServer) doServe() error {
  136. action := "started"
  137. if s.fd != 0 {
  138. action = "reloaded"
  139. }
  140. s.server.Logger().Printf(
  141. "%d: %s server %s listening on [%s]",
  142. gproc.Pid(), s.getProto(), action, s.address,
  143. )
  144. s.status = ServerStatusRunning
  145. err := s.httpServer.Serve(s.listener)
  146. s.status = ServerStatusStopped
  147. return err
  148. }
  149. // getNetListener retrieves and returns the wrapped net.Listener.
  150. func (s *gracefulServer) getNetListener() (net.Listener, error) {
  151. var ln net.Listener
  152. var err error
  153. if s.fd > 0 {
  154. f := os.NewFile(s.fd, "")
  155. ln, err = net.FileListener(f)
  156. if err != nil {
  157. err = fmt.Errorf("%d: net.FileListener error: %v", gproc.Pid(), err)
  158. return nil, err
  159. }
  160. } else {
  161. ln, err = net.Listen("tcp", s.httpServer.Addr)
  162. if err != nil {
  163. err = fmt.Errorf("%d: net.Listen error: %v", gproc.Pid(), err)
  164. }
  165. }
  166. return ln, err
  167. }
  168. // shutdown shuts down the server gracefully.
  169. func (s *gracefulServer) shutdown() {
  170. if s.status == ServerStatusStopped {
  171. return
  172. }
  173. if err := s.httpServer.Shutdown(context.Background()); err != nil {
  174. s.server.Logger().Errorf(
  175. "%d: %s server [%s] shutdown error: %v",
  176. gproc.Pid(), s.getProto(), s.address, err,
  177. )
  178. }
  179. }
  180. // close shuts down the server forcibly.
  181. func (s *gracefulServer) close() {
  182. if s.status == ServerStatusStopped {
  183. return
  184. }
  185. if err := s.httpServer.Close(); err != nil {
  186. s.server.Logger().Errorf(
  187. "%d: %s server [%s] closed error: %v",
  188. gproc.Pid(), s.getProto(), s.address, err,
  189. )
  190. }
  191. }