gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. // Copyright 2023 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package graceful
  4. import (
  5. "context"
  6. "runtime/pprof"
  7. "sync"
  8. "time"
  9. "code.gitea.io/gitea/modules/gtprof"
  10. )
  11. // FIXME: it seems that there is a bug when using systemd Type=notify: the "Install Page" (INSTALL_LOCK=false) doesn't notify properly.
  12. // At the moment, no idea whether it also affects Windows Service, or whether it's a regression bug. It needs to be investigated later.
  13. type systemdNotifyMsg string
  14. const (
  15. readyMsg systemdNotifyMsg = "READY=1"
  16. stoppingMsg systemdNotifyMsg = "STOPPING=1"
  17. reloadingMsg systemdNotifyMsg = "RELOADING=1"
  18. watchdogMsg systemdNotifyMsg = "WATCHDOG=1"
  19. )
  20. func statusMsg(msg string) systemdNotifyMsg {
  21. return systemdNotifyMsg("STATUS=" + msg)
  22. }
  23. // Manager manages the graceful shutdown process
  24. type Manager struct {
  25. ctx context.Context
  26. isChild bool
  27. forked bool
  28. lock sync.RWMutex
  29. state state
  30. shutdownCtx context.Context
  31. hammerCtx context.Context
  32. terminateCtx context.Context
  33. managerCtx context.Context
  34. shutdownCtxCancel context.CancelFunc
  35. hammerCtxCancel context.CancelFunc
  36. terminateCtxCancel context.CancelFunc
  37. managerCtxCancel context.CancelFunc
  38. runningServerWaitGroup sync.WaitGroup
  39. terminateWaitGroup sync.WaitGroup
  40. createServerCond sync.Cond
  41. createdServer int
  42. shutdownRequested chan struct{}
  43. toRunAtShutdown []func()
  44. toRunAtTerminate []func()
  45. }
  46. func newGracefulManager(ctx context.Context) *Manager {
  47. manager := &Manager{ctx: ctx, shutdownRequested: make(chan struct{})}
  48. manager.createServerCond.L = &sync.Mutex{}
  49. manager.prepare(ctx)
  50. manager.start()
  51. return manager
  52. }
  53. func (g *Manager) prepare(ctx context.Context) {
  54. g.terminateCtx, g.terminateCtxCancel = context.WithCancel(ctx)
  55. g.shutdownCtx, g.shutdownCtxCancel = context.WithCancel(ctx)
  56. g.hammerCtx, g.hammerCtxCancel = context.WithCancel(ctx)
  57. g.managerCtx, g.managerCtxCancel = context.WithCancel(ctx)
  58. g.terminateCtx = pprof.WithLabels(g.terminateCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-terminate"))
  59. g.shutdownCtx = pprof.WithLabels(g.shutdownCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-shutdown"))
  60. g.hammerCtx = pprof.WithLabels(g.hammerCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-hammer"))
  61. g.managerCtx = pprof.WithLabels(g.managerCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-manager"))
  62. if !g.setStateTransition(stateInit, stateRunning) {
  63. panic("invalid graceful manager state: transition from init to running failed")
  64. }
  65. }
  66. // DoImmediateHammer causes an immediate hammer
  67. func (g *Manager) DoImmediateHammer() {
  68. g.notify(statusMsg("Sending immediate hammer"))
  69. g.doHammerTime(0 * time.Second)
  70. }
  71. // DoGracefulShutdown causes a graceful shutdown
  72. func (g *Manager) DoGracefulShutdown() {
  73. g.lock.Lock()
  74. select {
  75. case <-g.shutdownRequested:
  76. default:
  77. close(g.shutdownRequested)
  78. }
  79. forked := g.forked
  80. g.lock.Unlock()
  81. if !forked {
  82. g.notify(stoppingMsg)
  83. } else {
  84. g.notify(statusMsg("Shutting down after fork"))
  85. }
  86. g.doShutdown()
  87. }
  88. // RegisterServer registers the running of a listening server, in the case of unix this means that the parent process can now die.
  89. // Any call to RegisterServer must be matched by a call to ServerDone
  90. func (g *Manager) RegisterServer() {
  91. KillParent()
  92. g.runningServerWaitGroup.Add(1)
  93. }