diff --git a/cmd/server/main.go b/cmd/server/main.go index 15676a4..00ebbf0 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -1,10 +1,14 @@ package main import ( + "context" "log" "log/slog" "net/http" "os" + "os/signal" + "syscall" + "time" "gitea.leeworks.dev/0xwheatyz/gitea-mobile/internal/config" giteaclient "gitea.leeworks.dev/0xwheatyz/gitea-mobile/internal/gitea" @@ -36,8 +40,35 @@ func main() { handler = middleware.Auth(cfg.SessionSecret, cfg.GiteaToken)(handler) handler = middleware.Logging()(handler) - slog.Info("server starting", "addr", cfg.ListenAddr, "gitea_url", cfg.GiteaURL) - if err := http.ListenAndServe(cfg.ListenAddr, handler); err != nil { - log.Fatalf("server error: %v", err) + srv := &http.Server{ + Addr: cfg.ListenAddr, + Handler: handler, } + + // Channel to receive shutdown signals. + quit := make(chan os.Signal, 1) + signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT) + + // Start server in a goroutine. + go func() { + slog.Info("server starting", "addr", cfg.ListenAddr, "gitea_url", cfg.GiteaURL) + if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { + log.Fatalf("server error: %v", err) + } + }() + + // Block until a shutdown signal is received. + sig := <-quit + slog.Info("shutdown signal received, draining in-flight requests", "signal", sig.String()) + + // Give in-flight requests up to 15 seconds to complete. + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + + if err := srv.Shutdown(ctx); err != nil { + slog.Error("server forced to shutdown", "error", err) + os.Exit(1) + } + + slog.Info("server stopped gracefully") }