summaryrefslogtreecommitdiff
path: root/internal/health/health.go
blob: d1c9df3697d41675b938d3d17ddc3ad3aa10a4a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 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)
}