Documentation
¶
Overview ¶
Package rsvp provides a simple way to run an HTTP server with graceful shutdown functionality.
It listens for specified OS signals (SIGTERM and SIGINT by default) and shuts down the server gracefully, by calling http.Server.Shutdown, when one of those signals is received. In particular, this allows the server to finish handling any in-flight HTTP requests before shutting down, instead of terminating immediately.
The simplest way to use rsvp is to replace calls to http.ListenAndServe with rsvp.ListenAndServe, which has the same signature but adds graceful shutdown functionality.
For more advanced use cases, you can create an http.Server and call rsvp.Run directly.
The default behavior can be customized with the provided Option functions.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNilServer = errors.New("rsvp: server is nil")
Functions ¶
func ListenAndServe ¶
ListenAndServe is a convenience wrapper around Run that creates an http.Server with the given address and handler.
ListenAndServe is intended primarily as a drop-in replacement for http.ListenAndServe which adds graceful shutdown functionality.
Example ¶
package main
import (
"log"
"net/http"
"strconv"
"time"
"github.com/jbarham/rsvp"
)
func main() {
http.HandleFunc("GET /{delay}", func(w http.ResponseWriter, r *http.Request) {
delay, err := strconv.Atoi(r.PathValue("delay"))
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
log.Printf("Starting request with %ds delay...", delay)
time.Sleep(time.Duration(delay) * time.Second)
log.Print("Finished request")
})
rsvp.ListenAndServe(":8080", nil)
}
Output:
func Run ¶
Run starts the HTTP server and shuts it down gracefully when a signal is received.
Run returns any error that occurs during startup or shutdown. It returns nil on successful shutdown.
Example ¶
package main
import (
"fmt"
"log"
"net/http"
"sync"
"github.com/jbarham/rsvp"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, world!")
})
server := &http.Server{Addr: ":8080"}
// Registered shutdown functions are run in separate goroutines,
// so we need to wait for them to finish before exiting main.
var wg sync.WaitGroup
wg.Add(1)
server.RegisterOnShutdown(func() {
log.Print("Server is shutting down, cleaning up...")
// Close database connections, WebSockets etc
wg.Done()
})
rsvp.Run(server)
wg.Wait()
log.Print("Shutdown functions complete, exiting")
}
Output:
Types ¶
type Option ¶
type Option func(*runner)
Option functions configure the behavior of the graceful shutdown process.
func WithLogFunc ¶
WithLogFunc sets the logging function that will be used to log messages during the server lifecycle.
The default logging function calls log.Println. Setting the logging function to nil will disable logging.
Example ¶
package main
import (
"fmt"
"log/slog"
"net/http"
"github.com/jbarham/rsvp"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, world!")
})
logFunc := func(msg string) {
slog.Info(msg)
}
rsvp.ListenAndServe(":8080", nil, rsvp.WithLogFunc(logFunc))
}
Output:
func WithShutdownContext ¶
WithShutdownContext sets the context that will be used for the shutdown process. The default context is context.Background.
If a timeout is also set by WithTimeout, the shutdown will be canceled if it takes longer than the timeout, even if the context itself has not been canceled.
func WithSignals ¶
WithSignals sets the signals that will trigger the shutdown process. The default signals are SIGTERM and SIGINT.
func WithTLS ¶ added in v1.1.0
WithTLS sets the TLS certificate and key files to use for the server.
If both certFile and keyFile are provided, the server will use TLS. Otherwise, it will use plain text HTTP.
func WithTimeout ¶
WithTimeout sets the timeout for the shutdown process. If the shutdown takes longer than this, shutdown will be canceled and Run will return the context.DeadlineExceeded error.
Without a timeout (the default case), the shutdown process will wait indefinitely for in-flight requests to finish before shutting down the server. In practice, service managers like systemd will send a final non-catchable SIGKILL signal after a certain timeout if the process has not exited.
Example ¶
package main
import (
"log"
"net/http"
"time"
"github.com/jbarham/rsvp"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
log.Print("A slow request is being processed...")
time.Sleep(10 * time.Second)
log.Print("Slow request completed")
})
if err := rsvp.ListenAndServe(":8080", nil, rsvp.WithTimeout(5*time.Second)); err != nil {
log.Fatalf("Shutdown error: %s", err)
}
}
Output: