Graceful: Allow graceful restart for unix sockets (#9113)
Previously we could not handle graceful restarts for http over unix sockets. These can now be handled.
This commit is contained in:
parent
bb2c0c3729
commit
e3f22ad2cc
4 changed files with 31 additions and 30 deletions
29
cmd/web.go
29
cmd/web.go
|
@ -60,7 +60,7 @@ func runHTTPRedirector() {
|
||||||
http.Redirect(w, r, target, http.StatusTemporaryRedirect)
|
http.Redirect(w, r, target, http.StatusTemporaryRedirect)
|
||||||
})
|
})
|
||||||
|
|
||||||
var err = runHTTP(source, context2.ClearHandler(handler))
|
var err = runHTTP("tcp", source, context2.ClearHandler(handler))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to start port redirection: %v", err)
|
log.Fatal("Failed to start port redirection: %v", err)
|
||||||
|
@ -77,12 +77,12 @@ func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler)
|
||||||
go func() {
|
go func() {
|
||||||
log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect)
|
log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect)
|
||||||
// all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here)
|
// all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here)
|
||||||
var err = runHTTP(setting.HTTPAddr+":"+setting.PortToRedirect, certManager.HTTPHandler(http.HandlerFunc(runLetsEncryptFallbackHandler)))
|
var err = runHTTP("tcp", setting.HTTPAddr+":"+setting.PortToRedirect, certManager.HTTPHandler(http.HandlerFunc(runLetsEncryptFallbackHandler)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err)
|
log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return runHTTPSWithTLSConfig(listenAddr, certManager.TLSConfig(), context2.ClearHandler(m))
|
return runHTTPSWithTLSConfig("tcp", listenAddr, certManager.TLSConfig(), context2.ClearHandler(m))
|
||||||
}
|
}
|
||||||
|
|
||||||
func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
|
func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -171,7 +171,7 @@ func runWeb(ctx *cli.Context) error {
|
||||||
switch setting.Protocol {
|
switch setting.Protocol {
|
||||||
case setting.HTTP:
|
case setting.HTTP:
|
||||||
NoHTTPRedirector()
|
NoHTTPRedirector()
|
||||||
err = runHTTP(listenAddr, context2.ClearHandler(m))
|
err = runHTTP("tcp", listenAddr, context2.ClearHandler(m))
|
||||||
case setting.HTTPS:
|
case setting.HTTPS:
|
||||||
if setting.EnableLetsEncrypt {
|
if setting.EnableLetsEncrypt {
|
||||||
err = runLetsEncrypt(listenAddr, setting.Domain, setting.LetsEncryptDirectory, setting.LetsEncryptEmail, context2.ClearHandler(m))
|
err = runLetsEncrypt(listenAddr, setting.Domain, setting.LetsEncryptDirectory, setting.LetsEncryptEmail, context2.ClearHandler(m))
|
||||||
|
@ -182,7 +182,7 @@ func runWeb(ctx *cli.Context) error {
|
||||||
} else {
|
} else {
|
||||||
NoHTTPRedirector()
|
NoHTTPRedirector()
|
||||||
}
|
}
|
||||||
err = runHTTPS(listenAddr, setting.CertFile, setting.KeyFile, context2.ClearHandler(m))
|
err = runHTTPS("tcp", listenAddr, setting.CertFile, setting.KeyFile, context2.ClearHandler(m))
|
||||||
case setting.FCGI:
|
case setting.FCGI:
|
||||||
NoHTTPRedirector()
|
NoHTTPRedirector()
|
||||||
// FCGI listeners are provided as stdin - this is orthogonal to the LISTEN_FDS approach
|
// FCGI listeners are provided as stdin - this is orthogonal to the LISTEN_FDS approach
|
||||||
|
@ -200,25 +200,8 @@ func runWeb(ctx *cli.Context) error {
|
||||||
}()
|
}()
|
||||||
err = fcgi.Serve(listener, context2.ClearHandler(m))
|
err = fcgi.Serve(listener, context2.ClearHandler(m))
|
||||||
case setting.UnixSocket:
|
case setting.UnixSocket:
|
||||||
// This could potentially be inherited using LISTEN_FDS but currently
|
|
||||||
// these cannot be inherited
|
|
||||||
NoHTTPRedirector()
|
NoHTTPRedirector()
|
||||||
NoMainListener()
|
err = runHTTP("unix", listenAddr, context2.ClearHandler(m))
|
||||||
if err := os.Remove(listenAddr); err != nil && !os.IsNotExist(err) {
|
|
||||||
log.Fatal("Failed to remove unix socket directory %s: %v", listenAddr, err)
|
|
||||||
}
|
|
||||||
var listener *net.UnixListener
|
|
||||||
listener, err = net.ListenUnix("unix", &net.UnixAddr{Name: listenAddr, Net: "unix"})
|
|
||||||
if err != nil {
|
|
||||||
break // Handle error after switch
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: add proper implementation of signal capture on all protocols
|
|
||||||
// execute this on SIGTERM or SIGINT: listener.Close()
|
|
||||||
if err = os.Chmod(listenAddr, os.FileMode(setting.UnixSocketPermission)); err != nil {
|
|
||||||
log.Fatal("Failed to set permission of unix socket: %v", err)
|
|
||||||
}
|
|
||||||
err = http.Serve(listener, context2.ClearHandler(m))
|
|
||||||
default:
|
default:
|
||||||
log.Fatal("Invalid protocol: %s", setting.Protocol)
|
log.Fatal("Invalid protocol: %s", setting.Protocol)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,16 +11,16 @@ import (
|
||||||
"code.gitea.io/gitea/modules/graceful"
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
)
|
)
|
||||||
|
|
||||||
func runHTTP(listenAddr string, m http.Handler) error {
|
func runHTTP(network, listenAddr string, m http.Handler) error {
|
||||||
return graceful.HTTPListenAndServe("tcp", listenAddr, m)
|
return graceful.HTTPListenAndServe(network, listenAddr, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHTTPS(listenAddr, certFile, keyFile string, m http.Handler) error {
|
func runHTTPS(network, listenAddr, certFile, keyFile string, m http.Handler) error {
|
||||||
return graceful.HTTPListenAndServeTLS("tcp", listenAddr, certFile, keyFile, m)
|
return graceful.HTTPListenAndServeTLS(network, listenAddr, certFile, keyFile, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHTTPSWithTLSConfig(listenAddr string, tlsConfig *tls.Config, m http.Handler) error {
|
func runHTTPSWithTLSConfig(network, listenAddr string, tlsConfig *tls.Config, m http.Handler) error {
|
||||||
return graceful.HTTPListenAndServeTLSConfig("tcp", listenAddr, tlsConfig, m)
|
return graceful.HTTPListenAndServeTLSConfig(network, listenAddr, tlsConfig, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoHTTPRedirector tells our cleanup routine that we will not be using a fallback http redirector
|
// NoHTTPRedirector tells our cleanup routine that we will not be using a fallback http redirector
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -165,15 +166,27 @@ func GetListenerUnix(network string, address *net.UnixAddr) (*net.UnixListener,
|
||||||
if isSameAddr(l.Addr(), address) {
|
if isSameAddr(l.Addr(), address) {
|
||||||
providedListeners = append(providedListeners[:i], providedListeners[i+1:]...)
|
providedListeners = append(providedListeners[:i], providedListeners[i+1:]...)
|
||||||
activeListeners = append(activeListeners, l)
|
activeListeners = append(activeListeners, l)
|
||||||
return l.(*net.UnixListener), nil
|
unixListener := l.(*net.UnixListener)
|
||||||
|
unixListener.SetUnlinkOnClose(true)
|
||||||
|
return unixListener, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a fresh listener
|
// make a fresh listener
|
||||||
|
if err := os.Remove(address.Name); err != nil && !os.IsNotExist(err) {
|
||||||
|
return nil, fmt.Errorf("Failed to remove unix socket %s: %v", address.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
l, err := net.ListenUnix(network, address)
|
l, err := net.ListenUnix(network, address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileMode := os.FileMode(setting.UnixSocketPermission)
|
||||||
|
if err = os.Chmod(address.Name, fileMode); err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to set permission of unix socket to %s: %v", fileMode.String(), err)
|
||||||
|
}
|
||||||
|
|
||||||
activeListeners = append(activeListeners, l)
|
activeListeners = append(activeListeners, l)
|
||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ package graceful
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -48,6 +49,10 @@ func RestartProcess() (int, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if unixListener, ok := l.(*net.UnixListener); ok {
|
||||||
|
unixListener.SetUnlinkOnClose(false)
|
||||||
|
}
|
||||||
// Remember to close these at the end.
|
// Remember to close these at the end.
|
||||||
defer files[i].Close()
|
defer files[i].Close()
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue