package app import ( "context" "fmt" "io" "net/http" "os" "os/signal" "syscall" "time" "github.com/gabehf/kanpeki/app/middleware" "github.com/gabehf/kanpeki/internal/cfg" "github.com/gabehf/kanpeki/internal/db" "github.com/gabehf/kanpeki/internal/logger" "github.com/go-chi/chi/v5" chimiddleware "github.com/go-chi/chi/v5/middleware" "github.com/rs/zerolog" ) func NewServer(logger *zerolog.Logger, cfg *cfg.Config, db db.DB) http.Handler { mux := chi.NewRouter() // bind general middleware to mux mux.Use(middleware.Logger(logger)) mux.Use(chimiddleware.RealIP) mux.Use(chimiddleware.Recoverer) // call router binds on mux bindRoutes(mux, logger, cfg, db) return mux } func Run( ctx context.Context, getenv func(string) string, stdout io.Writer, db db.DB, ) error { cfg, err := cfg.Load(getenv) if err != nil { return fmt.Errorf("failed to load configuration: %v", err) } logger := logger.Get(cfg).Output(stdout) srv := NewServer(&logger, cfg, db) httpServer := &http.Server{ Addr: cfg.ListenAddr, Handler: srv, } logger.Info().Msg("listening on " + cfg.ListenAddr) if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { return err } // Wait for interrupt signal to gracefully shutdown the server with a timeout of 10 seconds. // Use a buffered channel to avoid missing signals as recommended for signal.Notify quit := make(chan os.Signal, 1) signal.Notify(quit, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) <-quit logger.Info().Msg("recieved server shutdown notice") ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() logger.Info().Msg("waiting for all processes to finish...") if err := httpServer.Shutdown(ctx); err != nil { return err } logger.Info().Msg("shutdown successful") return nil }