eef60a4302
Secret UUID-based webhook endpoint for CI image push notifications. Project/stage matching via glob patterns, auto-creation of unknown projects from image inspection. Fix JSON response injection.
80 lines
2.0 KiB
Go
80 lines
2.0 KiB
Go
package health
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// DefaultRetries is the number of health check attempts before declaring failure.
|
|
const DefaultRetries = 3
|
|
|
|
// DefaultRetryInterval is the pause between health check retries.
|
|
const DefaultRetryInterval = 5 * time.Second
|
|
|
|
// DefaultTimeout is the HTTP timeout for a single health check attempt.
|
|
const DefaultTimeout = 10 * time.Second
|
|
|
|
// Checker performs HTTP health checks against a container endpoint.
|
|
type Checker struct {
|
|
httpClient *http.Client
|
|
retries int
|
|
retryInterval time.Duration
|
|
}
|
|
|
|
// New creates a Checker with default settings.
|
|
func New() *Checker {
|
|
return &Checker{
|
|
httpClient: &http.Client{
|
|
Timeout: DefaultTimeout,
|
|
},
|
|
retries: DefaultRetries,
|
|
retryInterval: DefaultRetryInterval,
|
|
}
|
|
}
|
|
|
|
// Check performs an HTTP GET health check against the given URL.
|
|
// It retries up to the configured number of times, waiting retryInterval between attempts.
|
|
// Returns nil on the first successful (2xx) response, or the last error encountered.
|
|
func (c *Checker) Check(ctx context.Context, url string) error {
|
|
var lastErr error
|
|
|
|
for attempt := 0; attempt < c.retries; attempt++ {
|
|
if attempt > 0 {
|
|
select {
|
|
case <-ctx.Done():
|
|
return fmt.Errorf("health check cancelled: %w", ctx.Err())
|
|
case <-time.After(c.retryInterval):
|
|
}
|
|
}
|
|
|
|
lastErr = c.doCheck(ctx, url)
|
|
if lastErr == nil {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return fmt.Errorf("health check failed after %d attempts: %w", c.retries, lastErr)
|
|
}
|
|
|
|
// doCheck performs a single HTTP GET health check.
|
|
func (c *Checker) doCheck(ctx context.Context, url string) error {
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("create health check request: %w", err)
|
|
}
|
|
|
|
resp, err := c.httpClient.Do(req)
|
|
if err != nil {
|
|
return fmt.Errorf("health check request to %s: %w", url, err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
return fmt.Errorf("health check %s returned status %d", url, resp.StatusCode)
|
|
}
|
|
|
|
return nil
|
|
}
|