diff --git a/main.go b/main.go index fe9f036..3cdf78a 100644 --- a/main.go +++ b/main.go @@ -1,8 +1,13 @@ package main import ( + "context" "me-fit/handler" "me-fit/utils" + "os/signal" + "sync" + "syscall" + "time" "database/sql" "log" @@ -15,48 +20,66 @@ import ( ) func main() { + run(context.Background()) +} + +func run(ctx context.Context) { slog.Info("Starting server...") + ctx, cancel := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM) + defer cancel() + + // init env err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } utils.MustInitEnv() + // init db db, err := sql.Open("sqlite3", "./data.db") if err != nil { log.Fatal("Could not open Database data.db: ", err) } defer db.Close() - utils.MustRunMigrations(db, "") - startPrometheus() - - var server = http.Server{ - Addr: ":8080", - Handler: handler.GetHandler(db), - } - slog.Info("Starting server on " + server.Addr) - - err = server.ListenAndServe() - if err != nil { - panic(err) - } -} - -func startPrometheus() { - - var prometheusServer = http.Server{ + // init servers + prometheusServer := &http.Server{ Addr: ":8081", Handler: promhttp.Handler(), } + httpServer := &http.Server{ + Addr: ":8080", + Handler: handler.GetHandler(db), + } + go startServer(prometheusServer) + go startServer(httpServer) - go func() { - slog.Info("Starting prometheus server on " + prometheusServer.Addr) - err := prometheusServer.ListenAndServe() - if err != nil { - log.Fatal("Could not start prometheus server: ", err) - } - }() + // graceful shutdown + var wg sync.WaitGroup + wg.Add(2) + go shutdownServer(httpServer, ctx, &wg) + go shutdownServer(prometheusServer, ctx, &wg) + wg.Wait() +} + +func startServer(s *http.Server) { + slog.Info("Starting server on " + s.Addr) + if err := s.ListenAndServe(); err != nil && err != http.ErrServerClosed { + slog.Error("error listening and serving: " + err.Error()) + } +} + +func shutdownServer(s *http.Server, ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() + <-ctx.Done() + shutdownCtx := context.Background() + shutdownCtx, cancel := context.WithTimeout(shutdownCtx, 10*time.Second) + defer cancel() + if err := s.Shutdown(shutdownCtx); err != nil { + slog.Error("error shutting down http server: " + err.Error()) + } else { + slog.Info("Gracefully stopped http server on " + s.Addr) + } }