wip: optimize graceful shutdown

This commit is contained in:
Kevin Franklin Kim 2023-12-14 08:34:47 +01:00
parent 3dd86ae626
commit e100f0730a
No known key found for this signature in database
3 changed files with 74 additions and 2 deletions

View File

@ -4,8 +4,10 @@ import (
"context"
"net/http"
"sync"
"syscall"
"time"
"github.com/foomo/keel/interfaces"
"github.com/foomo/keel/service"
"go.uber.org/zap"
@ -15,6 +17,7 @@ import (
func main() {
svr := keel.NewServer(
//keel.WithLogger(zap.NewExample()),
keel.WithHTTPZapService(true),
keel.WithHTTPViperService(true),
keel.WithHTTPPrometheusService(true),
@ -28,15 +31,70 @@ func main() {
// create demo service
svs := http.NewServeMux()
svs.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
l.Info("handling request...")
time.Sleep(3 * time.Second)
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("OK"))
l.Info("... handled request")
})
svr.AddService(
service.NewHTTP(l, "demo", "localhost:8080", svs),
)
svr.Run()
svr.AddCloser(interfaces.CloseFunc(func(ctx context.Context) error {
l.Info("custom closer")
return nil
}))
go svr.Run()
time.Sleep(1 * time.Second)
l.Info("1. starting test")
{
l.Info("2. checking healthz")
readiness(l, "http://localhost:9400/healthz/readiness")
}
go func() {
l.Info("2. sending request")
if r, err := http.Get("http://localhost:8080"); err != nil {
l.Fatal(err.Error())
} else {
l.Info(" /", zap.Int("status", r.StatusCode))
}
}()
time.Sleep(100 * time.Millisecond)
l.Info("3. sending shutdown signal")
if err := syscall.Kill(syscall.Getpid(), syscall.SIGTERM); err != nil {
l.Fatal(err.Error())
}
{
l.Info("2. checking healthz")
readiness(l, "http://localhost:9400/healthz/readiness")
}
l.Info("4. waiting for shutdown")
time.Sleep(10 * time.Second)
l.Info(" done")
}
func readiness(l *zap.Logger, url string) {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
l.Error(err.Error())
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
l.Error(err.Error())
return
}
l.Info(url, zap.Int("status", resp.StatusCode))
}
func waitGroup(ctx context.Context, l *zap.Logger) {

View File

@ -4,6 +4,14 @@ import (
"context"
)
type CloseHandler struct {
Value func(ctx context.Context) error
}
func (r CloseHandler) Close(ctx context.Context) error {
return r.Value(ctx)
}
// Closer interface
type Closer interface {
Close()
@ -23,3 +31,9 @@ type CloserWithContext interface {
type ErrorCloserWithContext interface {
Close(ctx context.Context) error
}
func CloseFunc(v func(ctx context.Context) error) CloseHandler {
return CloseHandler{
Value: v,
}
}

View File

@ -65,7 +65,7 @@ type Server struct {
func NewServer(opts ...Option) *Server {
inst := &Server{
shutdownTimeout: 30 * time.Second,
shutdownSignals: []os.Signal{os.Interrupt, syscall.SIGTERM},
shutdownSignals: []os.Signal{syscall.SIGTERM},
syncReadmers: []interfaces.Readmer{},
syncProbes: map[healthz.Type][]interface{}{},
ctx: context.Background(),