package healthcheckcmd import ( "context" "errors" "flag" "fmt" "log/slog" "net" "net/http" "net/url" "git.maronato.dev/maronato/goshort/cmd/shared" "git.maronato.dev/maronato/goshort/internal/config" "git.maronato.dev/maronato/goshort/internal/util/logging" "github.com/peterbourgon/ff/v3/ffcli" ) var ErrFailedHealthCheck = errors.New("healthcheck failed") func New(cfg *config.Config) *ffcli.Command { // Create the flagset and register the flags. fs := flag.NewFlagSet("goshort healthcheck", flag.ContinueOnError) shared.RegisterBaseFlags(fs, cfg) // Create the command and options cmd := shared.NewCommand(cfg, exec) opts := shared.NewSharedCmdOptions() // Return the ffcli command. return &ffcli.Command{ Name: "healthcheck", ShortUsage: "goshort healthcheck [flags]", ShortHelp: "Calls the healthcheck endpoint of the server", FlagSet: fs, Exec: cmd.Exec, Options: opts, } } // exec makes a request to the healthcheck endpoint. // If the request fails, return an error // Otherwise, return nil. func exec(ctx context.Context, cfg *config.Config) error { l := logging.FromCtx(ctx) l.Debug("Executing healthcheck command", slog.Any("config", cfg)) addr := url.URL{ Host: net.JoinHostPort(cfg.Host, cfg.Port), Scheme: "http", Path: "/healthz", } req, err := http.NewRequestWithContext(ctx, http.MethodGet, addr.String(), http.NoBody) if err != nil { return fmt.Errorf("error creating request: %w", err) } resp, err := http.DefaultClient.Do(req) if err != nil { return fmt.Errorf("error making request: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf( "healthcheck endpoint returned status code %d: %w", resp.StatusCode, ErrFailedHealthCheck, ) } return nil }