You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

server_hooks.go 3.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package graceful
  5. import (
  6. "errors"
  7. "fmt"
  8. "os"
  9. "runtime"
  10. "time"
  11. "code.gitea.io/gitea/modules/log"
  12. "code.gitea.io/gitea/modules/setting"
  13. )
  14. // shutdown closes the listener so that no new connections are accepted
  15. // and starts a goroutine that will hammer (stop all running requests) the server
  16. // after setting.GracefulHammerTime.
  17. func (srv *Server) shutdown() {
  18. // only shutdown if we're running.
  19. if srv.getState() != stateRunning {
  20. return
  21. }
  22. srv.setState(stateShuttingDown)
  23. if setting.GracefulHammerTime >= 0 {
  24. go srv.hammerTime(setting.GracefulHammerTime)
  25. }
  26. if srv.OnShutdown != nil {
  27. srv.OnShutdown()
  28. }
  29. err := srv.listener.Close()
  30. if err != nil {
  31. log.Error("PID: %d Listener.Close() error: %v", os.Getpid(), err)
  32. } else {
  33. log.Info("PID: %d Listener (%s) closed.", os.Getpid(), srv.listener.Addr())
  34. }
  35. }
  36. // hammerTime forces the server to shutdown in a given timeout - whether it
  37. // finished outstanding requests or not. if Read/WriteTimeout are not set or the
  38. // max header size is very big a connection could hang...
  39. //
  40. // srv.Serve() will not return until all connections are served. this will
  41. // unblock the srv.wg.Wait() in Serve() thus causing ListenAndServe* functions to
  42. // return.
  43. func (srv *Server) hammerTime(d time.Duration) {
  44. defer func() {
  45. // We call srv.wg.Done() until it panics.
  46. // This happens if we call Done() when the WaitGroup counter is already at 0
  47. // So if it panics -> we're done, Serve() will return and the
  48. // parent will goroutine will exit.
  49. if r := recover(); r != nil {
  50. log.Error("WaitGroup at 0: Error: %v", r)
  51. }
  52. }()
  53. if srv.getState() != stateShuttingDown {
  54. return
  55. }
  56. time.Sleep(d)
  57. log.Warn("Forcefully shutting down parent")
  58. for {
  59. if srv.getState() == stateTerminate {
  60. break
  61. }
  62. srv.wg.Done()
  63. // Give other goroutines a chance to finish before we forcibly stop them.
  64. runtime.Gosched()
  65. }
  66. }
  67. func (srv *Server) fork() error {
  68. runningServerReg.Lock()
  69. defer runningServerReg.Unlock()
  70. // only one server instance should fork!
  71. if runningServersForked {
  72. return errors.New("another process already forked. Ignoring this one")
  73. }
  74. runningServersForked = true
  75. // We need to move the file logs to append pids
  76. setting.RestartLogsWithPIDSuffix()
  77. _, err := RestartProcess()
  78. return err
  79. }
  80. // RegisterPreSignalHook registers a function to be run before the signal handler for
  81. // a given signal. These are not mutex locked and should therefore be only called before Serve.
  82. func (srv *Server) RegisterPreSignalHook(sig os.Signal, f func()) (err error) {
  83. for _, s := range hookableSignals {
  84. if s == sig {
  85. srv.PreSignalHooks[sig] = append(srv.PreSignalHooks[sig], f)
  86. return
  87. }
  88. }
  89. err = fmt.Errorf("Signal %v is not supported", sig)
  90. return
  91. }
  92. // RegisterPostSignalHook registers a function to be run after the signal handler for
  93. // a given signal. These are not mutex locked and should therefore be only called before Serve.
  94. func (srv *Server) RegisterPostSignalHook(sig os.Signal, f func()) (err error) {
  95. for _, s := range hookableSignals {
  96. if s == sig {
  97. srv.PostSignalHooks[sig] = append(srv.PostSignalHooks[sig], f)
  98. return
  99. }
  100. }
  101. err = fmt.Errorf("Signal %v is not supported", sig)
  102. return
  103. }