diff options
author | Marc Pervaz Boocha <mboocha@sudomsg.com> | 2025-08-07 22:51:34 +0530 |
---|---|---|
committer | Marc Pervaz Boocha <mboocha@sudomsg.com> | 2025-08-07 22:51:34 +0530 |
commit | 1326bb4103694d7ceac23b23329997ea2207a3f6 (patch) | |
tree | 72eb0065b597121c4e54518d303f5d15de40336d /http/http.go | |
parent | Fixed missing signals (diff) | |
download | kit-1326bb4103694d7ceac23b23329997ea2207a3f6.tar kit-1326bb4103694d7ceac23b23329997ea2207a3f6.tar.gz kit-1326bb4103694d7ceac23b23329997ea2207a3f6.tar.bz2 kit-1326bb4103694d7ceac23b23329997ea2207a3f6.tar.lz kit-1326bb4103694d7ceac23b23329997ea2207a3f6.tar.xz kit-1326bb4103694d7ceac23b23329997ea2207a3f6.tar.zst kit-1326bb4103694d7ceac23b23329997ea2207a3f6.zip |
Added File Mode to sockets and socket activation
Diffstat (limited to '')
-rw-r--r-- | http/http.go | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/http/http.go b/http/http.go new file mode 100644 index 0000000..063c1e8 --- /dev/null +++ b/http/http.go @@ -0,0 +1,85 @@ +package http + +import ( + "context" + "fmt" + "go.sudomsg.com/kit/logging" + "golang.org/x/sync/errgroup" + "log/slog" + "net" + "net/http" +) + +// RunHTTPServers runs HTTP servers concurrently on all provided listeners. +// +// The provided handler is used for all servers. +// Servers respond to context cancellation by performing a graceful shutdown with a timeout of 10 seconds. +// +// Logging is performed using the slog.Logger extracted from context. +// Each server logs startup, shutdown, and errors. +// +// This function blocks until all servers have stopped or an error occurs. +func RunHTTPServers(ctx context.Context, lns Listeners, handler http.Handler) error { + g, ctx := errgroup.WithContext(ctx) + + for _, ln := range lns { + g.Go(func() error { + logger, ctx := logging.With(ctx, "address", ln.Addr()) + + srv := &http.Server{ + Addr: ln.Addr().String(), + Handler: handler, + BaseContext: func(l net.Listener) context.Context { + return ctx + }, + ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError), + } + + logger.Log(ctx, slog.LevelInfo, "HTTP server serving") + + if err := httpServeContext(ctx, srv, ln); err != nil { + return fmt.Errorf("HTTP server Serve Error: %w", err) + } + return nil + }) + + } + return g.Wait() +} + +func httpServeContext(ctx context.Context, srv *http.Server, ln net.Listener) error { + logger := logging.FromContext(ctx) + + shutdownErrCh := make(chan error, 1) + + go func() { + <-ctx.Done() + shutdownErrCh <- httpServeShutdown(srv, logger) + }() + serveErr := srv.Serve(ln) + + // Always wait for shutdown result + shutdownErr := <-shutdownErrCh + + // Prioritize Serve error + if serveErr != nil && !errors.Is(serveErr, http.ErrServerClosed) { + return fmt.Errorf("http serve error: %w", serveErr) + } + if shutdownErr != nil { + return fmt.Errorf("http shutdown error: %w", shutdownErr) + } + return nil +} + +func httpServeShutdown(srv *http.Server, logger *slog.Logger) error { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + if err := srv.Shutdown(ctx); err != nil { + logger.Log(ctx, slog.LevelWarn, "HTTP server Shutdown Error", slog.Any("error", err)) + return err + } + + logger.Log(ctx, slog.LevelInfo, "HTTP Server Shutdown Complete") + return nil +} |