// Package health checks whether a freshly (re)started app is up, by polling // its declared health endpoint - shared by both internal/deploy and skiff // config's own restart-and-verify sequence. package health import ( "context" "fmt" "net/http" "time" "skiff/internal/appmeta" "skiff/internal/layout" ) func WaitHealthy(ctx context.Context, meta appmeta.Meta) error { url := fmt.Sprintf("http://%s:%d%s", meta.IP, meta.Port, meta.HealthPath) deadline := time.Now().Add(layout.HealthTimeoutSecs * time.Second) client := &http.Client{Timeout: 2 * time.Second} var lastErr error for time.Now().Before(deadline) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return err } resp, err := client.Do(req) if err == nil { resp.Body.Close() if resp.StatusCode < 300 { return nil } lastErr = fmt.Errorf("status %d", resp.StatusCode) } else { lastErr = err } time.Sleep(500 * time.Millisecond) } return fmt.Errorf("never became healthy at %s: %w", url, lastErr) }