package main import ( "me-fit/handler" "me-fit/types" "me-fit/utils" "os" "context" "database/sql" "log" "log/slog" "net/http" "os/signal" "sync" "syscall" "time" "github.com/joho/godotenv" _ "github.com/mattn/go-sqlite3" "github.com/prometheus/client_golang/prometheus/promhttp" ) func main() { err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } run(context.Background(), os.Getenv) } func run(ctx context.Context, env func(string) string) { ctx, cancel := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM) defer cancel() slog.Info("Starting server...") // init server settings serverSettings := types.NewServerSettingsFromEnv(env) // init db db, err := sql.Open("sqlite3", serverSettings.DbPath) if err != nil { log.Fatal("Could not open Database data.db: ", err) } defer db.Close() utils.MustRunMigrations(db, "") // init servers prometheusServer := &http.Server{ Addr: ":8081", Handler: promhttp.Handler(), } httpServer := &http.Server{ Addr: ":8080", Handler: handler.GetHandler(db, serverSettings), } go startServer(prometheusServer) go startServer(httpServer) // 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) } }