Skip to content

Commit

Permalink
webserver: shutdown via close if using RPC (sourcegraph#516)
Browse files Browse the repository at this point in the history
Our RPC system does not support shutdown and hijacks the underlying http
connection. This means shutdown is ineffective and just waits 10s before
calling close. Lets just quit faster in that case.

Test Plan: Run zoekt-webserver with and without rpc. Run kill and
observe behaviour.
  • Loading branch information
keegancsmith authored Jan 10, 2023
1 parent 5bbffb3 commit 38d5f90
Showing 1 changed file with 36 additions and 8 deletions.
44 changes: 36 additions & 8 deletions cmd/zoekt-webserver/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,17 @@ func main() {
}
}()

if err := shutdownOnSignal(srv); err != nil {
log.Fatalf("http.Server.Shutdown: %v", err)
if s.RPC {
// Our RPC system does not support shutdown and hijacks the underlying
// http connection. This means shutdown is ineffective and just waits 10s
// before calling close. Lets just quit faster in that case.
if err := closeOnSignal(srv); err != nil {
log.Fatalf("http.Server.Close: %v", err)
}
} else {
if err := shutdownOnSignal(srv); err != nil {
log.Fatalf("http.Server.Shutdown: %v", err)
}
}
}

Expand All @@ -322,15 +331,34 @@ func addProxyHandler(mux *http.ServeMux, socket string) {
mux.Handle("/indexserver/", http.StripPrefix("/indexserver/", http.HandlerFunc(proxy.ServeHTTP)))
}

// shutdownOnSignal will listen for SIGINT or SIGTERM and call
// srv.Shutdown. Note it doesn't call anything else for shutting down. Notably
// our RPC framework doesn't allow us to drain connections, so it when
// Shutdown is called all inflight RPC requests will be closed.
func shutdownOnSignal(srv *http.Server) error {
c := make(chan os.Signal, 3)
// shutdownSignalChan returns a channel which is listening for shutdown
// signals from the operating system. maxReads is an upper bound on how many
// times you will read the channel (used as buffer for signal.Notify).
func shutdownSignalChan(maxReads int) <-chan os.Signal {
c := make(chan os.Signal, maxReads)
signal.Notify(c, os.Interrupt) // terminal C-c and goreman
signal.Notify(c, syscall.SIGTERM) // Kubernetes
return c
}

// closeOnSignal will listen for SIGINT or SIGTERM and call srv.Close. This is
// not a graceful shutdown, see shutdownOnSignal.
func closeOnSignal(srv *http.Server) error {
c := shutdownSignalChan(1)
<-c

return srv.Close()
}

// shutdownOnSignal will listen for SIGINT or SIGTERM and call srv.Shutdown.
// Note it doesn't call anything else for shutting down. Notably our RPC
// framework doesn't allow us to drain connections, so when Shutdown we will
// wait 10s before closing.
//
// Note: the call site for shutdownOnSignal should use closeOnSignal instead
// if rpc mode is enabled due to the above limitation.
func shutdownOnSignal(srv *http.Server) error {
c := shutdownSignalChan(2)
<-c

// If we receive another signal, immediate shutdown
Expand Down

0 comments on commit 38d5f90

Please sign in to comment.