Health check answers 503 while report files cannot be written (closes #142)
check / check (push) Waiting to run
check / check (push) Waiting to run
The health check answered 200 "status":"ok" whatever happened, so a container whose report files could not be written stayed healthy while every report was refused with 500. The report buffer now says whether its last write of a report file failed. While it has, the health check's status is "error" and the handler answers 503 with the same fields, which fails the image's HEALTHCHECK. At start no write has failed, and the first write that succeeds brings back 200. A test removes DATA_DIR to make a write fail and checks the 503, then the 200 once a write succeeds again. Model: opus-5-5
This commit was merged in pull request #177.
This commit is contained in:
@@ -1074,6 +1074,51 @@ func TestReportsRefusedWhileWritesFail(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestHealthCheckFailsWhileWritesFail asks the health check handler
|
||||
// for its answer around a failed write. It answers 200 with
|
||||
// "status":"ok" at start, 503 with "status":"error" from the failed
|
||||
// write until a write succeeds, and 200 with "status":"ok" again after.
|
||||
func TestHealthCheckFailsWhileWritesFail(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
t.Setenv("DATA_DIR", dir)
|
||||
|
||||
buf, h := startBufferWithHandlers(t)
|
||||
|
||||
checkHealthCheck(t, h, "at start", http.StatusOK, "ok")
|
||||
|
||||
// A flush writes a file only when a report is waiting.
|
||||
err := buf.Append(map[string]string{"id": "kept"})
|
||||
if err != nil {
|
||||
t.Fatalf("append: %v", err)
|
||||
}
|
||||
|
||||
// With the data directory gone, the write has nowhere to go.
|
||||
err = os.Remove(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("remove data dir: %v", err)
|
||||
}
|
||||
|
||||
err = buf.Flush()
|
||||
if err == nil {
|
||||
t.Fatal("flush succeeded with the data directory gone")
|
||||
}
|
||||
|
||||
checkHealthCheck(t, h, "after the failed write",
|
||||
http.StatusServiceUnavailable, "error")
|
||||
|
||||
err = os.Mkdir(dir, 0o750)
|
||||
if err != nil {
|
||||
t.Fatalf("make data dir: %v", err)
|
||||
}
|
||||
|
||||
err = buf.Flush()
|
||||
if err != nil {
|
||||
t.Fatalf("flush with the data directory back: %v", err)
|
||||
}
|
||||
|
||||
checkHealthCheck(t, h, "after a write succeeded", http.StatusOK, "ok")
|
||||
}
|
||||
|
||||
// startBufferWithHandlers starts a Buffer and the Handlers that store
|
||||
// reports in it through fx, as main does, with the DATA_DIR the calling
|
||||
// test has set.
|
||||
@@ -1121,6 +1166,39 @@ func postReport(t *testing.T, h *handlers.Handlers, clientID string) int {
|
||||
return rec.Code
|
||||
}
|
||||
|
||||
// checkHealthCheck asks the health check handler for its answer, and
|
||||
// fails the test, saying when it asked, unless the answer has status
|
||||
// code wantCode and a "status" field of wantStatus.
|
||||
func checkHealthCheck(
|
||||
t *testing.T,
|
||||
h *handlers.Handlers,
|
||||
when string,
|
||||
wantCode int,
|
||||
wantStatus string,
|
||||
) {
|
||||
t.Helper()
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
req := httptest.NewRequestWithContext(t.Context(),
|
||||
http.MethodGet, "/.well-known/healthcheck", http.NoBody)
|
||||
h.HandleHealthCheck().ServeHTTP(rec, req)
|
||||
|
||||
var body struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &body)
|
||||
if err != nil {
|
||||
t.Fatalf("health check %s: body not JSON: %v (%q)",
|
||||
when, err, rec.Body.String())
|
||||
}
|
||||
|
||||
if rec.Code != wantCode || body.Status != wantStatus {
|
||||
t.Fatalf("health check %s: %d with status %q, want %d with %q",
|
||||
when, rec.Code, body.Status, wantCode, wantStatus)
|
||||
}
|
||||
}
|
||||
|
||||
// TestConcurrentAppendsStopAtCap appends from many goroutines at once
|
||||
// with room for exactly roomFor reports: exactly that many must be
|
||||
// taken, which holds only if Append checks and counts each report
|
||||
|
||||
Reference in New Issue
Block a user