package server import ( "context" "errors" "net/http" "os" "os/signal" "syscall" "allaboutapps.dev/aw/go-starter/cmd/db" "allaboutapps.dev/aw/go-starter/cmd/probe" "allaboutapps.dev/aw/go-starter/internal/api" "allaboutapps.dev/aw/go-starter/internal/api/router" "allaboutapps.dev/aw/go-starter/internal/config" "allaboutapps.dev/aw/go-starter/internal/util" "allaboutapps.dev/aw/go-starter/internal/util/command" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) type Flags struct { ProbeReadiness bool ApplyMigrations bool SeedFixtures bool } func New() *cobra.Command { var flags Flags cmd := &cobra.Command{ Use: "server", Short: "Starts the server", Long: `Starts the stateless RESTful JSON server Requires configuration through ENV and a fully migrated PostgreSQL database.`, Run: func(_ *cobra.Command, _ []string) { runServer(flags) }, } cmd.Flags().BoolVarP(&flags.ProbeReadiness, "probe", "p", false, "Probe readiness before startup.") cmd.Flags().BoolVarP(&flags.ApplyMigrations, "migrate", "m", false, "Apply migrations before startup.") cmd.Flags().BoolVarP(&flags.SeedFixtures, "seed", "s", false, "Seed fixtures into database before startup.") return cmd } func runServer(flags Flags) { err := command.WithServer(context.Background(), config.DefaultServiceConfigFromEnv(), func(ctx context.Context, s *api.Server) error { log := util.LogFromContext(ctx) if flags.ProbeReadiness { errs, err := probe.RunReadiness(ctx, s.Config, probe.ReadinessFlags{ Verbose: true, }) if err != nil { log.Fatal().Err(err).Msg("Failed to run readiness probes") } if len(errs) > 0 { log.Fatal().Errs("errs", errs).Msg("Unhealthy.") } } if flags.ApplyMigrations { _, err := db.ApplyMigrations(ctx, s.Config) if err != nil { log.Fatal().Err(err).Msg("Error while applying migrations") } } if flags.SeedFixtures { err := db.ApplySeedFixtures(ctx, s.Config) if err != nil { log.Fatal().Err(err).Msg("Error while applying seed fixtures") } } err := router.Init(s) if err != nil { log.Fatal().Err(err).Msg("Failed to initialize router") } go func() { if err := s.Start(); err != nil { if errors.Is(err, http.ErrServerClosed) { log.Info().Msg("Server closed") } else { log.Fatal().Err(err).Msg("Failed to start server") } } }() quit := make(chan os.Signal, 1) signal.Notify(quit, os.Interrupt, syscall.SIGTERM) <-quit return nil }) if err != nil { log.Fatal().Err(err).Msg("Failed to start server") } }