21/01/2024 - GO
In this example we are going to use signal.NotifyContext
to wait for actively running requests for a bit (5 seconds) before killing them if they run longer than that.
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
type app struct {
server *http.Server
shutdown time.Duration
}
func (a app) start() error {
if err := a.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
return err
}
return nil
}
func (a app) stop(ctx context.Context) error {
ctxNotify, stop := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM)
<-ctxNotify.Done()
stop()
ctxTimeout, cancel := context.WithTimeout(ctx, a.shutdown)
defer cancel()
if err := a.server.Shutdown(ctxTimeout); err != nil {
return err
}
return nil
}
func main() {
handler := http.DefaultServeMux
handler.HandleFunc("/", home)
server := &http.Server{
Addr: ":1234",
Handler: handler,
}
app := app{
server: server,
shutdown: time.Second * 5,
}
go func() {
log.Println("app is running")
if err := app.start(); err != nil {
log.Println("app start:", err)
return
}
}()
if err := app.stop(context.Background()); err != nil {
log.Println("dirty app stop with possible interruptions:", err)
} else {
log.Println("clean app stop without any interruption")
}
}
func home(w http.ResponseWriter, r *http.Request) {
log.Println("in")
time.Sleep(time.Second * 10) <- Adjust this in tests
log.Println("out")
}
As soon as calling $ curl http://0.0.0.0:1234/
use ctrl+c
.
time.Sleep(time.Second * 2)
$ go run -race main.go
2024/01/21 14:02:14 app is running
2024/01/21 14:02:35 in
^C
2024/01/21 14:02:37 out
2024/01/21 14:02:37 clean app stop without any interruption
time.Sleep(time.Second * 8)
$ go run -race main.go
2024/01/21 14:03:28 app is running
2024/01/21 14:03:32 in
^C
2024/01/21 14:03:37 dirty app stop with possible interruptions: context deadline exceeded