mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Refactor graceful manager to use shared code (#28073)
Make "windows" and "unix" share as much code as possible. No logic change.
This commit is contained in:
		| @@ -12,7 +12,6 @@ import ( | ||||
| 	"os/signal" | ||||
| 	"runtime/pprof" | ||||
| 	"strconv" | ||||
| 	"sync" | ||||
| 	"syscall" | ||||
| 	"time" | ||||
|  | ||||
| @@ -22,51 +21,6 @@ import ( | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| ) | ||||
|  | ||||
| // Manager manages the graceful shutdown process | ||||
| type Manager struct { | ||||
| 	isChild                bool | ||||
| 	forked                 bool | ||||
| 	lock                   *sync.RWMutex | ||||
| 	state                  state | ||||
| 	shutdownCtx            context.Context | ||||
| 	hammerCtx              context.Context | ||||
| 	terminateCtx           context.Context | ||||
| 	managerCtx             context.Context | ||||
| 	shutdownCtxCancel      context.CancelFunc | ||||
| 	hammerCtxCancel        context.CancelFunc | ||||
| 	terminateCtxCancel     context.CancelFunc | ||||
| 	managerCtxCancel       context.CancelFunc | ||||
| 	runningServerWaitGroup sync.WaitGroup | ||||
| 	createServerWaitGroup  sync.WaitGroup | ||||
| 	terminateWaitGroup     sync.WaitGroup | ||||
|  | ||||
| 	toRunAtShutdown  []func() | ||||
| 	toRunAtTerminate []func() | ||||
| } | ||||
|  | ||||
| func newGracefulManager(ctx context.Context) *Manager { | ||||
| 	manager := &Manager{ | ||||
| 		isChild: len(os.Getenv(listenFDsEnv)) > 0 && os.Getppid() > 1, | ||||
| 		lock:    &sync.RWMutex{}, | ||||
| 	} | ||||
| 	manager.createServerWaitGroup.Add(numberOfServersToCreate) | ||||
| 	manager.start(ctx) | ||||
| 	return manager | ||||
| } | ||||
|  | ||||
| type systemdNotifyMsg string | ||||
|  | ||||
| const ( | ||||
| 	readyMsg     systemdNotifyMsg = "READY=1" | ||||
| 	stoppingMsg  systemdNotifyMsg = "STOPPING=1" | ||||
| 	reloadingMsg systemdNotifyMsg = "RELOADING=1" | ||||
| 	watchdogMsg  systemdNotifyMsg = "WATCHDOG=1" | ||||
| ) | ||||
|  | ||||
| func statusMsg(msg string) systemdNotifyMsg { | ||||
| 	return systemdNotifyMsg("STATUS=" + msg) | ||||
| } | ||||
|  | ||||
| func pidMsg() systemdNotifyMsg { | ||||
| 	return systemdNotifyMsg("MAINPID=" + strconv.Itoa(os.Getpid())) | ||||
| } | ||||
| @@ -89,27 +43,13 @@ func (g *Manager) notify(msg systemdNotifyMsg) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (g *Manager) start(ctx context.Context) { | ||||
| 	// Make contexts | ||||
| 	g.terminateCtx, g.terminateCtxCancel = context.WithCancel(ctx) | ||||
| 	g.shutdownCtx, g.shutdownCtxCancel = context.WithCancel(ctx) | ||||
| 	g.hammerCtx, g.hammerCtxCancel = context.WithCancel(ctx) | ||||
| 	g.managerCtx, g.managerCtxCancel = context.WithCancel(ctx) | ||||
|  | ||||
| 	// Next add pprof labels to these contexts | ||||
| 	g.terminateCtx = pprof.WithLabels(g.terminateCtx, pprof.Labels("graceful-lifecycle", "with-terminate")) | ||||
| 	g.shutdownCtx = pprof.WithLabels(g.shutdownCtx, pprof.Labels("graceful-lifecycle", "with-shutdown")) | ||||
| 	g.hammerCtx = pprof.WithLabels(g.hammerCtx, pprof.Labels("graceful-lifecycle", "with-hammer")) | ||||
| 	g.managerCtx = pprof.WithLabels(g.managerCtx, pprof.Labels("graceful-lifecycle", "with-manager")) | ||||
|  | ||||
| func (g *Manager) start() { | ||||
| 	// Now label this and all goroutines created by this goroutine with the graceful-lifecycle manager | ||||
| 	pprof.SetGoroutineLabels(g.managerCtx) | ||||
| 	defer pprof.SetGoroutineLabels(ctx) | ||||
| 	defer pprof.SetGoroutineLabels(g.ctx) | ||||
|  | ||||
| 	g.isChild = len(os.Getenv(listenFDsEnv)) > 0 && os.Getppid() > 1 | ||||
|  | ||||
| 	// Set the running state & handle signals | ||||
| 	if !g.setStateTransition(stateInit, stateRunning) { | ||||
| 		panic("invalid graceful manager state: transition from init to running failed") | ||||
| 	} | ||||
| 	g.notify(statusMsg("Starting Gitea")) | ||||
| 	g.notify(pidMsg()) | ||||
| 	go g.handleSignals(g.managerCtx) | ||||
| @@ -118,11 +58,9 @@ func (g *Manager) start(ctx context.Context) { | ||||
| 	startupDone := make(chan struct{}) | ||||
| 	go func() { | ||||
| 		defer close(startupDone) | ||||
| 		// Wait till we're done getting all of the listeners and then close | ||||
| 		// the unused ones | ||||
| 		// Wait till we're done getting all the listeners and then close the unused ones | ||||
| 		g.createServerWaitGroup.Wait() | ||||
| 		// Ignore the error here there's not much we can do with it | ||||
| 		// They're logged in the CloseProvidedListeners function | ||||
| 		// Ignore the error here there's not much we can do with it, they're logged in the CloseProvidedListeners function | ||||
| 		_ = CloseProvidedListeners() | ||||
| 		g.notify(readyMsg) | ||||
| 	}() | ||||
| @@ -133,7 +71,7 @@ func (g *Manager) start(ctx context.Context) { | ||||
| 				return | ||||
| 			case <-g.IsShutdown(): | ||||
| 				func() { | ||||
| 					// When waitgroup counter goes negative it will panic - we don't care about this so we can just ignore it. | ||||
| 					// When WaitGroup counter goes negative it will panic - we don't care about this so we can just ignore it. | ||||
| 					defer func() { | ||||
| 						_ = recover() | ||||
| 					}() | ||||
| @@ -255,29 +193,3 @@ func (g *Manager) DoGracefulRestart() { | ||||
| 		g.doShutdown() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DoImmediateHammer causes an immediate hammer | ||||
| func (g *Manager) DoImmediateHammer() { | ||||
| 	g.notify(statusMsg("Sending immediate hammer")) | ||||
| 	g.doHammerTime(0 * time.Second) | ||||
| } | ||||
|  | ||||
| // DoGracefulShutdown causes a graceful shutdown | ||||
| func (g *Manager) DoGracefulShutdown() { | ||||
| 	g.lock.Lock() | ||||
| 	if !g.forked { | ||||
| 		g.lock.Unlock() | ||||
| 		g.notify(stoppingMsg) | ||||
| 	} else { | ||||
| 		g.lock.Unlock() | ||||
| 		g.notify(statusMsg("Shutting down after fork")) | ||||
| 	} | ||||
| 	g.doShutdown() | ||||
| } | ||||
|  | ||||
| // RegisterServer registers the running of a listening server, in the case of unix this means that the parent process can now die. | ||||
| // Any call to RegisterServer must be matched by a call to ServerDone | ||||
| func (g *Manager) RegisterServer() { | ||||
| 	KillParent() | ||||
| 	g.runningServerWaitGroup.Add(1) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user