GPLv3's "How to Apply These Terms" asks for a notice in each source file; this is the modern two-line SPDX form of it rather than the full paragraph. 82 files, including tests. The blank line after the header is load-bearing. In Go a comment block immediately preceding `package X` becomes the package doc comment, so without the separator the SPDX lines would be absorbed into the doc for the eleven packages whose doc.go (or main.go) opens with one, and `go doc` would print them. Verified it doesn't.
48 lines
1.3 KiB
Go
48 lines
1.3 KiB
Go
// SPDX-FileCopyrightText: 2026 LINUXexpert-org
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package recovery
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// WaitForHealthy polls url until it responds (any status - even 401 proves
|
|
// the HTTP server itself is up and routing requests, which is what this
|
|
// check exists to confirm) or timeout elapses, returning a descriptive
|
|
// error on timeout rather than hanging indefinitely. This is what makes
|
|
// recovery mode's startup supervised rather than fire-and-forget - see
|
|
// ARCHITECTURE.md §4.4.
|
|
func WaitForHealthy(ctx context.Context, httpClient *http.Client, url string, timeout time.Duration) error {
|
|
if httpClient == nil {
|
|
httpClient = &http.Client{Timeout: 5 * time.Second}
|
|
}
|
|
deadline := time.Now().Add(timeout)
|
|
var lastErr error
|
|
for time.Now().Before(deadline) {
|
|
if err := ctx.Err(); err != nil {
|
|
return err
|
|
}
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
resp, err := httpClient.Do(req)
|
|
if err != nil {
|
|
lastErr = err
|
|
} else {
|
|
resp.Body.Close()
|
|
return nil
|
|
}
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
case <-time.After(250 * time.Millisecond):
|
|
}
|
|
}
|
|
return fmt.Errorf("recovery: %s did not become reachable within %s: %w", url, timeout, lastErr)
|
|
}
|