aboutsummaryrefslogtreecommitdiffstats
path: root/modules/graceful/server.go
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2019-11-21 18:32:02 +0000
committertechknowlogick <techknowlogick@gitea.io>2019-11-21 13:32:02 -0500
commitcbaa1de9ec8ab1baa49357b660fab16a68097c84 (patch)
tree5f481d73c95ae24b91e7bb03abaa5cf921f806b5 /modules/graceful/server.go
parentd7ac9727bb5046118915cbb26b2dac1b7b27c9d4 (diff)
downloadgitea-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/server.go')
-rw-r--r--modules/graceful/server.go80
1 files changed, 22 insertions, 58 deletions
diff --git a/modules/graceful/server.go b/modules/graceful/server.go
index 896d547b46..c6692cbb75 100644
--- a/modules/graceful/server.go
+++ b/modules/graceful/server.go
@@ -1,5 +1,3 @@
-// +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.
@@ -19,37 +17,16 @@ import (
"code.gitea.io/gitea/modules/log"
)
-type state uint8
-
-const (
- stateInit state = iota
- stateRunning
- stateShuttingDown
- stateTerminate
-)
-
var (
- // RWMutex for when adding servers or shutting down
- runningServerReg sync.RWMutex
- runningServerWG sync.WaitGroup
- // ensure we only fork once
- runningServersForked bool
-
// DefaultReadTimeOut default read timeout
DefaultReadTimeOut time.Duration
// DefaultWriteTimeOut default write timeout
DefaultWriteTimeOut time.Duration
// DefaultMaxHeaderBytes default max header bytes
DefaultMaxHeaderBytes int
-
- // IsChild reports if we are a fork iff LISTEN_FDS is set and our parent PID is not 1
- IsChild = len(os.Getenv(listenFDs)) > 0 && os.Getppid() > 1
)
func init() {
- runningServerReg = sync.RWMutex{}
- runningServerWG = sync.WaitGroup{}
-
DefaultMaxHeaderBytes = 0 // use http.DefaultMaxHeaderBytes - which currently is 1 << 20 (1MB)
}
@@ -58,43 +35,29 @@ type ServeFunction = func(net.Listener) error
// Server represents our graceful server
type Server struct {
- network string
- address string
- listener net.Listener
- PreSignalHooks map[os.Signal][]func()
- PostSignalHooks map[os.Signal][]func()
- wg sync.WaitGroup
- sigChan chan os.Signal
- state state
- lock *sync.RWMutex
- BeforeBegin func(network, address string)
- OnShutdown func()
-}
-
-// WaitForServers waits for all running servers to finish
-func WaitForServers() {
- runningServerWG.Wait()
+ network string
+ address string
+ listener net.Listener
+ wg sync.WaitGroup
+ state state
+ lock *sync.RWMutex
+ BeforeBegin func(network, address string)
+ OnShutdown func()
}
// NewServer creates a server on network at provided address
func NewServer(network, address string) *Server {
- runningServerReg.Lock()
- defer runningServerReg.Unlock()
-
- if IsChild {
+ if Manager.IsChild() {
log.Info("Restarting new server: %s:%s on PID: %d", network, address, os.Getpid())
} else {
log.Info("Starting new server: %s:%s on PID: %d", network, address, os.Getpid())
}
srv := &Server{
- wg: sync.WaitGroup{},
- sigChan: make(chan os.Signal),
- PreSignalHooks: map[os.Signal][]func(){},
- PostSignalHooks: map[os.Signal][]func(){},
- state: stateInit,
- lock: &sync.RWMutex{},
- network: network,
- address: address,
+ wg: sync.WaitGroup{},
+ state: stateInit,
+ lock: &sync.RWMutex{},
+ network: network,
+ address: address,
}
srv.BeforeBegin = func(network, addr string) {
@@ -107,7 +70,7 @@ func NewServer(network, address string) *Server {
// ListenAndServe listens on the provided network address and then calls Serve
// to handle requests on incoming connections.
func (srv *Server) ListenAndServe(serve ServeFunction) error {
- go srv.handleSignals()
+ go srv.awaitShutdown()
l, err := GetListener(srv.network, srv.address)
if err != nil {
@@ -117,8 +80,6 @@ func (srv *Server) ListenAndServe(serve ServeFunction) error {
srv.listener = newWrappedListener(l, srv)
- KillParent()
-
srv.BeforeBegin(srv.network, srv.address)
return srv.Serve(serve)
@@ -150,7 +111,7 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string, serve ServeFuncti
// ListenAndServeTLSConfig listens on the provided network address and then calls
// Serve to handle requests on incoming TLS connections.
func (srv *Server) ListenAndServeTLSConfig(tlsConfig *tls.Config, serve ServeFunction) error {
- go srv.handleSignals()
+ go srv.awaitShutdown()
l, err := GetListener(srv.network, srv.address)
if err != nil {
@@ -161,7 +122,6 @@ func (srv *Server) ListenAndServeTLSConfig(tlsConfig *tls.Config, serve ServeFun
wl := newWrappedListener(l, srv)
srv.listener = tls.NewListener(wl, tlsConfig)
- KillParent()
srv.BeforeBegin(srv.network, srv.address)
return srv.Serve(serve)
@@ -178,12 +138,12 @@ func (srv *Server) ListenAndServeTLSConfig(tlsConfig *tls.Config, serve ServeFun
func (srv *Server) Serve(serve ServeFunction) error {
defer log.Debug("Serve() returning... (PID: %d)", syscall.Getpid())
srv.setState(stateRunning)
- runningServerWG.Add(1)
+ Manager.RegisterServer()
err := serve(srv.listener)
log.Debug("Waiting for connections to finish... (PID: %d)", syscall.Getpid())
srv.wg.Wait()
srv.setState(stateTerminate)
- runningServerWG.Done()
+ Manager.ServerDone()
// 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") {
return nil
@@ -205,6 +165,10 @@ func (srv *Server) setState(st state) {
srv.state = st
}
+type filer interface {
+ File() (*os.File, error)
+}
+
type wrappedListener struct {
net.Listener
stopped bool