summaryrefslogtreecommitdiff
path: root/internal/health/health.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/health/health.go')
-rw-r--r--internal/health/health.go40
1 files changed, 40 insertions, 0 deletions
diff --git a/internal/health/health.go b/internal/health/health.go
new file mode 100644
index 0000000..d1c9df3
--- /dev/null
+++ b/internal/health/health.go
@@ -0,0 +1,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)
+}