Graceful fixes (#8645)
* Only attempt to kill parent once * Apply suggestions from code review Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com> * Add waitgroup for running servers
This commit is contained in:
parent
7d1a7c05db
commit
f067e12859
5 changed files with 35 additions and 7 deletions
|
@ -13,6 +13,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/routers"
|
"code.gitea.io/gitea/routers"
|
||||||
|
@ -226,6 +227,7 @@ func runWeb(ctx *cli.Context) error {
|
||||||
log.Critical("Failed to start server: %v", err)
|
log.Critical("Failed to start server: %v", err)
|
||||||
}
|
}
|
||||||
log.Info("HTTP Listener: %s Closed", listenAddr)
|
log.Info("HTTP Listener: %s Closed", listenAddr)
|
||||||
|
graceful.WaitForServers()
|
||||||
log.Close()
|
log.Close()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,3 +9,8 @@ package graceful
|
||||||
|
|
||||||
// This file contains shims for windows builds
|
// This file contains shims for windows builds
|
||||||
const IsChild = false
|
const IsChild = false
|
||||||
|
|
||||||
|
// WaitForServers waits for all running servers to finish
|
||||||
|
func WaitForServers() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -12,8 +12,24 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"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 IsChild {
|
||||||
|
ppid := syscall.Getppid()
|
||||||
|
if ppid > 1 {
|
||||||
|
_ = syscall.Kill(ppid, syscall.SIGTERM)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// RestartProcess starts a new process passing it the active listeners. It
|
// RestartProcess starts a new process passing it the active listeners. It
|
||||||
// doesn't fork, but starts a new process using the same environment and
|
// 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
|
// arguments as when it was originally started. This allows for a newly
|
||||||
|
|
|
@ -31,6 +31,7 @@ const (
|
||||||
var (
|
var (
|
||||||
// RWMutex for when adding servers or shutting down
|
// RWMutex for when adding servers or shutting down
|
||||||
runningServerReg sync.RWMutex
|
runningServerReg sync.RWMutex
|
||||||
|
runningServerWG sync.WaitGroup
|
||||||
// ensure we only fork once
|
// ensure we only fork once
|
||||||
runningServersForked bool
|
runningServersForked bool
|
||||||
|
|
||||||
|
@ -47,6 +48,7 @@ var (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
runningServerReg = sync.RWMutex{}
|
runningServerReg = sync.RWMutex{}
|
||||||
|
runningServerWG = sync.WaitGroup{}
|
||||||
|
|
||||||
DefaultMaxHeaderBytes = 0 // use http.DefaultMaxHeaderBytes - which currently is 1 << 20 (1MB)
|
DefaultMaxHeaderBytes = 0 // use http.DefaultMaxHeaderBytes - which currently is 1 << 20 (1MB)
|
||||||
}
|
}
|
||||||
|
@ -69,6 +71,11 @@ type Server struct {
|
||||||
OnShutdown func()
|
OnShutdown func()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WaitForServers waits for all running servers to finish
|
||||||
|
func WaitForServers() {
|
||||||
|
runningServerWG.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
// NewServer creates a server on network at provided address
|
// NewServer creates a server on network at provided address
|
||||||
func NewServer(network, address string) *Server {
|
func NewServer(network, address string) *Server {
|
||||||
runningServerReg.Lock()
|
runningServerReg.Lock()
|
||||||
|
@ -110,9 +117,7 @@ func (srv *Server) ListenAndServe(serve ServeFunction) error {
|
||||||
|
|
||||||
srv.listener = newWrappedListener(l, srv)
|
srv.listener = newWrappedListener(l, srv)
|
||||||
|
|
||||||
if IsChild {
|
KillParent()
|
||||||
_ = syscall.Kill(syscall.Getppid(), syscall.SIGTERM)
|
|
||||||
}
|
|
||||||
|
|
||||||
srv.BeforeBegin(srv.network, srv.address)
|
srv.BeforeBegin(srv.network, srv.address)
|
||||||
|
|
||||||
|
@ -156,9 +161,7 @@ func (srv *Server) ListenAndServeTLSConfig(tlsConfig *tls.Config, serve ServeFun
|
||||||
wl := newWrappedListener(l, srv)
|
wl := newWrappedListener(l, srv)
|
||||||
srv.listener = tls.NewListener(wl, tlsConfig)
|
srv.listener = tls.NewListener(wl, tlsConfig)
|
||||||
|
|
||||||
if IsChild {
|
KillParent()
|
||||||
_ = syscall.Kill(syscall.Getppid(), syscall.SIGTERM)
|
|
||||||
}
|
|
||||||
srv.BeforeBegin(srv.network, srv.address)
|
srv.BeforeBegin(srv.network, srv.address)
|
||||||
|
|
||||||
return srv.Serve(serve)
|
return srv.Serve(serve)
|
||||||
|
@ -175,10 +178,12 @@ func (srv *Server) ListenAndServeTLSConfig(tlsConfig *tls.Config, serve ServeFun
|
||||||
func (srv *Server) Serve(serve ServeFunction) error {
|
func (srv *Server) Serve(serve ServeFunction) error {
|
||||||
defer log.Debug("Serve() returning... (PID: %d)", syscall.Getpid())
|
defer log.Debug("Serve() returning... (PID: %d)", syscall.Getpid())
|
||||||
srv.setState(stateRunning)
|
srv.setState(stateRunning)
|
||||||
|
runningServerWG.Add(1)
|
||||||
err := serve(srv.listener)
|
err := serve(srv.listener)
|
||||||
log.Debug("Waiting for connections to finish... (PID: %d)", syscall.Getpid())
|
log.Debug("Waiting for connections to finish... (PID: %d)", syscall.Getpid())
|
||||||
srv.wg.Wait()
|
srv.wg.Wait()
|
||||||
srv.setState(stateTerminate)
|
srv.setState(stateTerminate)
|
||||||
|
runningServerWG.Done()
|
||||||
// use of closed means that the listeners are closed - i.e. we should be shutting down - return nil
|
// use of closed means that the listeners are closed - i.e. we should be shutting down - return nil
|
||||||
if err != nil && strings.Contains(err.Error(), "use of closed") {
|
if err != nil && strings.Contains(err.Error(), "use of closed") {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -48,7 +48,7 @@ func (srv *Server) handleSignals() {
|
||||||
if setting.GracefulRestartable {
|
if setting.GracefulRestartable {
|
||||||
log.Info("PID: %d. Received SIGHUP. Forking...", pid)
|
log.Info("PID: %d. Received SIGHUP. Forking...", pid)
|
||||||
err := srv.fork()
|
err := srv.fork()
|
||||||
if err != nil {
|
if err != nil && err.Error() != "another process already forked. Ignoring this one" {
|
||||||
log.Error("Error whilst forking from PID: %d : %v", pid, err)
|
log.Error("Error whilst forking from PID: %d : %v", pid, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
Reference in a new issue