diff options
author | zeripath <art27@cantab.net> | 2019-11-21 18:32:02 +0000 |
---|---|---|
committer | techknowlogick <techknowlogick@gitea.io> | 2019-11-21 13:32:02 -0500 |
commit | cbaa1de9ec8ab1baa49357b660fab16a68097c84 (patch) | |
tree | 5f481d73c95ae24b91e7bb03abaa5cf921f806b5 /modules/graceful/restart_unix.go | |
parent | d7ac9727bb5046118915cbb26b2dac1b7b27c9d4 (diff) | |
download | gitea-cbaa1de9ec8ab1baa49357b660fab16a68097c84.tar.gz gitea-cbaa1de9ec8ab1baa49357b660fab16a68097c84.zip |
Add Graceful shutdown for Windows and hooks for shutdown of goroutines (#8964)
* Graceful Shutdown for windows and others
Restructures modules/graceful, adding shutdown for windows, removing and
replacing the old minwinsvc code.
Creates a new waitGroup - terminate which allows for goroutines to
finish up after the shutdown of the servers.
Shutdown and terminate hooks are added for goroutines.
* Remove unused functions - these can be added in a different PR
* Add startup timeout functionality
* Document STARTUP_TIMEOUT
Diffstat (limited to 'modules/graceful/restart_unix.go')
-rw-r--r-- | modules/graceful/restart_unix.go | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/modules/graceful/restart_unix.go b/modules/graceful/restart_unix.go new file mode 100644 index 0000000000..8c68965f5d --- /dev/null +++ b/modules/graceful/restart_unix.go @@ -0,0 +1,81 @@ +// +build !windows + +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. +// This code is heavily inspired by the archived gofacebook/gracenet/net.go handler + +package graceful + +import ( + "fmt" + "os" + "os/exec" + "strings" + "sync" + "syscall" +) + +var killParent sync.Once + +// KillParent sends the kill signal to the parent process if we are a child +func KillParent() { + killParent.Do(func() { + if Manager.IsChild() { + ppid := syscall.Getppid() + if ppid > 1 { + _ = syscall.Kill(ppid, syscall.SIGTERM) + } + } + }) +} + +// RestartProcess starts a new process passing it the active listeners. It +// doesn't fork, but starts a new process using the same environment and +// arguments as when it was originally started. This allows for a newly +// deployed binary to be started. It returns the pid of the newly started +// process when successful. +func RestartProcess() (int, error) { + listeners := getActiveListeners() + + // Extract the fds from the listeners. + files := make([]*os.File, len(listeners)) + for i, l := range listeners { + var err error + // Now, all our listeners actually have File() functions so instead of + // individually casting we just use a hacky interface + files[i], err = l.(filer).File() + if err != nil { + return 0, err + } + // Remember to close these at the end. + defer files[i].Close() + } + + // Use the original binary location. This works with symlinks such that if + // the file it points to has been changed we will use the updated symlink. + argv0, err := exec.LookPath(os.Args[0]) + if err != nil { + return 0, err + } + + // Pass on the environment and replace the old count key with the new one. + var env []string + for _, v := range os.Environ() { + if !strings.HasPrefix(v, listenFDs+"=") { + env = append(env, v) + } + } + env = append(env, fmt.Sprintf("%s=%d", listenFDs, len(listeners))) + + allFiles := append([]*os.File{os.Stdin, os.Stdout, os.Stderr}, files...) + process, err := os.StartProcess(argv0, os.Args, &os.ProcAttr{ + Dir: originalWD, + Env: env, + Files: allFiles, + }) + if err != nil { + return 0, err + } + return process.Pid, nil +} |