Skip to content

Commit f067e12

Browse files
authored
Graceful fixes (#8645)
* Only attempt to kill parent once * Apply suggestions from code review Co-Authored-By: guillep2k <[email protected]> * Add waitgroup for running servers
1 parent 7d1a7c0 commit f067e12

File tree

5 files changed

+35
-7
lines changed

5 files changed

+35
-7
lines changed

cmd/web.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"os"
1414
"strings"
1515

16+
"code.gitea.io/gitea/modules/graceful"
1617
"code.gitea.io/gitea/modules/log"
1718
"code.gitea.io/gitea/modules/setting"
1819
"code.gitea.io/gitea/routers"
@@ -226,6 +227,7 @@ func runWeb(ctx *cli.Context) error {
226227
log.Critical("Failed to start server: %v", err)
227228
}
228229
log.Info("HTTP Listener: %s Closed", listenAddr)
230+
graceful.WaitForServers()
229231
log.Close()
230232
return nil
231233
}

modules/graceful/graceful_windows.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,8 @@ package graceful
99

1010
// This file contains shims for windows builds
1111
const IsChild = false
12+
13+
// WaitForServers waits for all running servers to finish
14+
func WaitForServers() {
15+
16+
}

modules/graceful/restart.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,24 @@ import (
1212
"os"
1313
"os/exec"
1414
"strings"
15+
"sync"
16+
"syscall"
1517
)
1618

19+
var killParent sync.Once
20+
21+
// KillParent sends the kill signal to the parent process if we are a child
22+
func KillParent() {
23+
killParent.Do(func() {
24+
if IsChild {
25+
ppid := syscall.Getppid()
26+
if ppid > 1 {
27+
_ = syscall.Kill(ppid, syscall.SIGTERM)
28+
}
29+
}
30+
})
31+
}
32+
1733
// RestartProcess starts a new process passing it the active listeners. It
1834
// doesn't fork, but starts a new process using the same environment and
1935
// arguments as when it was originally started. This allows for a newly

modules/graceful/server.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const (
3131
var (
3232
// RWMutex for when adding servers or shutting down
3333
runningServerReg sync.RWMutex
34+
runningServerWG sync.WaitGroup
3435
// ensure we only fork once
3536
runningServersForked bool
3637

@@ -47,6 +48,7 @@ var (
4748

4849
func init() {
4950
runningServerReg = sync.RWMutex{}
51+
runningServerWG = sync.WaitGroup{}
5052

5153
DefaultMaxHeaderBytes = 0 // use http.DefaultMaxHeaderBytes - which currently is 1 << 20 (1MB)
5254
}
@@ -69,6 +71,11 @@ type Server struct {
6971
OnShutdown func()
7072
}
7173

74+
// WaitForServers waits for all running servers to finish
75+
func WaitForServers() {
76+
runningServerWG.Wait()
77+
}
78+
7279
// NewServer creates a server on network at provided address
7380
func NewServer(network, address string) *Server {
7481
runningServerReg.Lock()
@@ -110,9 +117,7 @@ func (srv *Server) ListenAndServe(serve ServeFunction) error {
110117

111118
srv.listener = newWrappedListener(l, srv)
112119

113-
if IsChild {
114-
_ = syscall.Kill(syscall.Getppid(), syscall.SIGTERM)
115-
}
120+
KillParent()
116121

117122
srv.BeforeBegin(srv.network, srv.address)
118123

@@ -156,9 +161,7 @@ func (srv *Server) ListenAndServeTLSConfig(tlsConfig *tls.Config, serve ServeFun
156161
wl := newWrappedListener(l, srv)
157162
srv.listener = tls.NewListener(wl, tlsConfig)
158163

159-
if IsChild {
160-
_ = syscall.Kill(syscall.Getppid(), syscall.SIGTERM)
161-
}
164+
KillParent()
162165
srv.BeforeBegin(srv.network, srv.address)
163166

164167
return srv.Serve(serve)
@@ -175,10 +178,12 @@ func (srv *Server) ListenAndServeTLSConfig(tlsConfig *tls.Config, serve ServeFun
175178
func (srv *Server) Serve(serve ServeFunction) error {
176179
defer log.Debug("Serve() returning... (PID: %d)", syscall.Getpid())
177180
srv.setState(stateRunning)
181+
runningServerWG.Add(1)
178182
err := serve(srv.listener)
179183
log.Debug("Waiting for connections to finish... (PID: %d)", syscall.Getpid())
180184
srv.wg.Wait()
181185
srv.setState(stateTerminate)
186+
runningServerWG.Done()
182187
// use of closed means that the listeners are closed - i.e. we should be shutting down - return nil
183188
if err != nil && strings.Contains(err.Error(), "use of closed") {
184189
return nil

modules/graceful/server_signals.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func (srv *Server) handleSignals() {
4848
if setting.GracefulRestartable {
4949
log.Info("PID: %d. Received SIGHUP. Forking...", pid)
5050
err := srv.fork()
51-
if err != nil {
51+
if err != nil && err.Error() != "another process already forked. Ignoring this one" {
5252
log.Error("Error whilst forking from PID: %d : %v", pid, err)
5353
}
5454
} else {

0 commit comments

Comments
 (0)