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.

manager_unix.go 3.6 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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. "context"
  8. "errors"
  9. "os"
  10. "os/signal"
  11. "sync"
  12. "syscall"
  13. "time"
  14. "code.gitea.io/gitea/modules/log"
  15. "code.gitea.io/gitea/modules/setting"
  16. )
  17. type gracefulManager struct {
  18. isChild bool
  19. forked bool
  20. lock *sync.RWMutex
  21. state state
  22. shutdown chan struct{}
  23. hammer chan struct{}
  24. terminate chan struct{}
  25. runningServerWaitGroup sync.WaitGroup
  26. createServerWaitGroup sync.WaitGroup
  27. terminateWaitGroup sync.WaitGroup
  28. }
  29. func newGracefulManager(ctx context.Context) *gracefulManager {
  30. manager := &gracefulManager{
  31. isChild: len(os.Getenv(listenFDs)) > 0 && os.Getppid() > 1,
  32. lock: &sync.RWMutex{},
  33. }
  34. manager.createServerWaitGroup.Add(numberOfServersToCreate)
  35. manager.Run(ctx)
  36. return manager
  37. }
  38. func (g *gracefulManager) Run(ctx context.Context) {
  39. g.setState(stateRunning)
  40. go g.handleSignals(ctx)
  41. c := make(chan struct{})
  42. go func() {
  43. defer close(c)
  44. // Wait till we're done getting all of the listeners and then close
  45. // the unused ones
  46. g.createServerWaitGroup.Wait()
  47. // Ignore the error here there's not much we can do with it
  48. // They're logged in the CloseProvidedListeners function
  49. _ = CloseProvidedListeners()
  50. }()
  51. if setting.StartupTimeout > 0 {
  52. go func() {
  53. select {
  54. case <-c:
  55. return
  56. case <-g.IsShutdown():
  57. return
  58. case <-time.After(setting.StartupTimeout):
  59. log.Error("Startup took too long! Shutting down")
  60. g.doShutdown()
  61. }
  62. }()
  63. }
  64. }
  65. func (g *gracefulManager) handleSignals(ctx context.Context) {
  66. signalChannel := make(chan os.Signal, 1)
  67. signal.Notify(
  68. signalChannel,
  69. syscall.SIGHUP,
  70. syscall.SIGUSR1,
  71. syscall.SIGUSR2,
  72. syscall.SIGINT,
  73. syscall.SIGTERM,
  74. syscall.SIGTSTP,
  75. )
  76. pid := syscall.Getpid()
  77. for {
  78. select {
  79. case sig := <-signalChannel:
  80. switch sig {
  81. case syscall.SIGHUP:
  82. if setting.GracefulRestartable {
  83. log.Info("PID: %d. Received SIGHUP. Forking...", pid)
  84. err := g.doFork()
  85. if err != nil && err.Error() != "another process already forked. Ignoring this one" {
  86. log.Error("Error whilst forking from PID: %d : %v", pid, err)
  87. }
  88. } else {
  89. log.Info("PID: %d. Received SIGHUP. Not set restartable. Shutting down...", pid)
  90. g.doShutdown()
  91. }
  92. case syscall.SIGUSR1:
  93. log.Info("PID %d. Received SIGUSR1.", pid)
  94. case syscall.SIGUSR2:
  95. log.Warn("PID %d. Received SIGUSR2. Hammering...", pid)
  96. g.doHammerTime(0 * time.Second)
  97. case syscall.SIGINT:
  98. log.Warn("PID %d. Received SIGINT. Shutting down...", pid)
  99. g.doShutdown()
  100. case syscall.SIGTERM:
  101. log.Warn("PID %d. Received SIGTERM. Shutting down...", pid)
  102. g.doShutdown()
  103. case syscall.SIGTSTP:
  104. log.Info("PID %d. Received SIGTSTP.", pid)
  105. default:
  106. log.Info("PID %d. Received %v.", pid, sig)
  107. }
  108. case <-ctx.Done():
  109. log.Warn("PID: %d. Background context for manager closed - %v - Shutting down...", pid, ctx.Err())
  110. g.doShutdown()
  111. }
  112. }
  113. }
  114. func (g *gracefulManager) doFork() error {
  115. g.lock.Lock()
  116. if g.forked {
  117. g.lock.Unlock()
  118. return errors.New("another process already forked. Ignoring this one")
  119. }
  120. g.forked = true
  121. g.lock.Unlock()
  122. // We need to move the file logs to append pids
  123. setting.RestartLogsWithPIDSuffix()
  124. _, err := RestartProcess()
  125. return err
  126. }
  127. func (g *gracefulManager) RegisterServer() {
  128. KillParent()
  129. g.runningServerWaitGroup.Add(1)
  130. }