Files
go-kit/httpd/httpd.go
Jan Tytgat c0349917de Refactor httpd functions
Signed-off-by: Jan Tytgat <jan.tytgat@corelayer.eu>
2025-04-29 22:27:14 +02:00

91 lines
3.1 KiB
Go

package httpd
import (
"context"
"errors"
"fmt"
"log/slog"
"net"
"net/http"
"strconv"
"time"
"git.flexabyte.io/flexabyte/go-kit/slogd"
)
func RunHttpServer(ctx context.Context, log *slog.Logger, listenAddress string, port int, h http.Handler, shutdownTimeout time.Duration) error {
s := &http.Server{
Addr: listenAddress + ":" + strconv.Itoa(port),
Handler: h}
log.LogAttrs(ctx, slogd.LevelTrace, "starting http server", slog.String("listenAddress", fmt.Sprintf("http://%s", s.Addr)))
shutdownCtx, shutdownCancel := context.WithCancel(ctx)
defer shutdownCancel()
// Run goroutine to handle graceful shutdown
idleConnectionsClosed := make(chan struct{})
go shutdown(shutdownCtx, log, s, shutdownTimeout, idleConnectionsClosed)
var err error
if err = s.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
// Error starting or closing listener:
log.LogAttrs(ctx, slogd.LevelError, "http server start failed", slog.String("error", err.Error()))
return err
}
<-idleConnectionsClosed
return err
}
func RunSocketHttpServer(ctx context.Context, log *slog.Logger, socketPath string, h http.Handler, shutdownTimeout time.Duration) error {
s := &http.Server{
Handler: h}
log.LogAttrs(ctx, slogd.LevelTrace, "starting http server", slog.String("socket", s.Addr))
shutdownCtx, shutdownCancel := context.WithCancel(ctx)
defer shutdownCancel()
// Run goroutine to handle graceful shutdown
idleConnectionsClosed := make(chan struct{})
go shutdown(shutdownCtx, log, s, shutdownTimeout, idleConnectionsClosed)
var err error
var config = new(net.ListenConfig)
var socket net.Listener
if socket, err = config.Listen(ctx, "unix", socketPath); err != nil {
log.LogAttrs(ctx, slogd.LevelError, "failed to listen on socket", slog.String("error", err.Error()))
return err
}
if err = s.Serve(socket); err != nil && !errors.Is(err, http.ErrServerClosed) {
// Error starting or closing listener:
log.LogAttrs(ctx, slogd.LevelError, "http server start failed", slog.String("error", err.Error()))
return err
}
<-idleConnectionsClosed
return err
}
func shutdown(ctx context.Context, log *slog.Logger, s *http.Server, shutdownTimeout time.Duration, idleConnectionsClosed chan struct{}) {
log.LogAttrs(ctx, slogd.LevelTrace, "awaiting shutdown signal for http server", slog.String("listenAddress", s.Addr))
<-ctx.Done()
// When shutdown signal is received, create a new context with the configured shutdown timeout
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), shutdownTimeout)
defer shutdownCancel()
log.LogAttrs(shutdownCtx, slogd.LevelTrace, "shutdown signal received for http server", slog.String("listenAddress", s.Addr))
time.Sleep(2 * time.Second)
// We received an interrupt signal, shut down.
if err := s.Shutdown(shutdownCtx); err != nil {
// Error from closing listeners, or context timeout:
log.LogAttrs(ctx, slogd.LevelTrace, "shutdown for http server failed", slog.String("listenAddress", s.Addr), slog.Any("error", err))
}
log.LogAttrs(shutdownCtx, slogd.LevelTrace, "shutdown for http server completed", slog.String("listenAddress", s.Addr))
close(idleConnectionsClosed)
}