本站源代码
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

122 lines
3.3KB

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