Repository navigation
fix(boot): non-fatal schema discovery, /health 503 with diagnostic #125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 13 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
ab41fee
fix(boot): non-fatal schema discovery, /health 503 with diagnostic
EricAndrechek ab6cfbb
test(discovery): drop redundant time.Sleep in cancel test + comment fix
EricAndrechek 2c57041
docs(agents): record non-fatal boot as Key Design Decision #15
EricAndrechek 2144b3a
fix(docs,test): startupProbe in k8s example + extract clamp helper
EricAndrechek db7cdf5
Merge branch 'main' into issue-95
EricAndrechek dcb452b
fix(boot,docs): address CodeRabbit review on #125
EricAndrechek e6676ac
test(discovery): relax SucceedsOnFirstAttempt wall-clock bound to 250ms
EricAndrechek 48d56d9
test(discovery): JSON slog handler + WithTimeout ctx in happy-path test
EricAndrechek ec5ea43
test: close the contract on non-fatal boot — chain + auto-refresh + p…
EricAndrechek 3d9f964
test: address CodeRabbit round 5 on ec5ea43
EricAndrechek 11a3b4d
build: include ./cmd/... in test-unit + file-level cov excludes
EricAndrechek f854274
build(cov): per-suite excludes + inline threshold gate
EricAndrechek 32ae077
fix(discovery): skip onAttempt during ctx cancellation in RetryRefresh
EricAndrechek 4c93545
Merge remote-tracking branch 'origin/main' into issue-95
EricAndrechek 04709d8
refactor(main): tie KV/DLQ inits to process-lifetime ctx
EricAndrechek File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "context" | ||
| "net" | ||
| "net/http" | ||
| "net/http/httptest" | ||
| "strconv" | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| // runHealthCheck is the Dockerfile HEALTHCHECK probe — the bridge between | ||
| // the in-process /health endpoint and the docker daemon's container-health | ||
| // state. These tests pin the contract that holds the boot-non-fatal promise | ||
| // together: when wavehouse is boot-degraded, /health returns 503 and the | ||
| // probe must return 1 so Docker marks the container unhealthy. Without this | ||
| // coverage, a regression that swallowed non-200 responses would silently | ||
| // re-create the "stuck container" failure mode the PR is solving. | ||
| // | ||
| // Tests don't run in parallel because they all mutate WH_SERVER_PORT. | ||
| // t.Setenv handles save/restore. | ||
|
|
||
| // portFromListener pulls the integer port off a net.Listener. We use the | ||
| // listener directly (rather than parsing httptest.Server.URL) so the same | ||
| // helper works for both started-server cases and the connection-refused | ||
| // case where we listen-then-close to claim a known-unused port. | ||
| func portFromListener(t *testing.T, ln net.Listener) string { | ||
| t.Helper() | ||
| addr, ok := ln.Addr().(*net.TCPAddr) | ||
| require.True(t, ok, "listener should be a TCP listener") | ||
| return strconv.Itoa(addr.Port) | ||
| } | ||
|
|
||
| func TestRunHealthCheck_Success(t *testing.T) { | ||
| srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| // The probe targets /health specifically — pin that contract here | ||
| // so a refactor that points the probe at /ready (which requires | ||
| // ClickHouse) doesn't slip through silently. | ||
| assert.Equal(t, "/health", r.URL.Path) | ||
| w.WriteHeader(http.StatusOK) | ||
| })) | ||
| defer srv.Close() | ||
|
|
||
| t.Setenv("WH_SERVER_PORT", portFromListener(t, srv.Listener)) | ||
| assert.Equal(t, 0, runHealthCheck(), "200 OK should map to exit 0") | ||
| } | ||
|
|
||
| func TestRunHealthCheck_BootDegraded503(t *testing.T) { | ||
| // This is the user-facing contract under boot-degraded state: the | ||
| // in-process /health returns 503 with a diagnostic body, the probe | ||
| // sees the non-200, returns 1, and Docker's HEALTHCHECK marks the | ||
| // container unhealthy. The K8s startupProbe path in deployment.md | ||
| // relies on exactly this signal. | ||
| srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { | ||
| w.WriteHeader(http.StatusServiceUnavailable) | ||
| _, _ = w.Write([]byte(`{"status":"degraded","error":"schema discovery: connection refused"}`)) | ||
| })) | ||
| defer srv.Close() | ||
|
|
||
| t.Setenv("WH_SERVER_PORT", portFromListener(t, srv.Listener)) | ||
| assert.Equal(t, 1, runHealthCheck(), "503 should map to exit 1 — Docker marks unhealthy") | ||
| } | ||
|
|
||
| func TestRunHealthCheck_ConnectionRefused(t *testing.T) { | ||
| // Wavehouse hasn't bound :8080 yet (e.g., still in the pre-listen | ||
| // phase of `run()`, or crashed entirely). Bind+close a TCP listener | ||
| // to claim a port that's now guaranteed unused, so the probe's GET | ||
| // gets a real connect-refused rather than a slow timeout. | ||
| var lc net.ListenConfig | ||
| ln, err := lc.Listen(context.Background(), "tcp", "127.0.0.1:0") | ||
| require.NoError(t, err) | ||
| port := portFromListener(t, ln) | ||
| require.NoError(t, ln.Close()) | ||
|
|
||
| t.Setenv("WH_SERVER_PORT", port) | ||
| assert.Equal(t, 1, runHealthCheck(), "connection refused should map to exit 1") | ||
| } | ||
|
|
||
| func TestRunHealthCheck_InvalidPortEnv(t *testing.T) { | ||
| // Garbage env var should fail fast at the parse step, not propagate | ||
| // a confusing dial error. Catches the case where an operator | ||
| // fat-fingers WH_SERVER_PORT in a deployment manifest. | ||
| t.Setenv("WH_SERVER_PORT", "not-a-number") | ||
| assert.Equal(t, 1, runHealthCheck(), "non-integer WH_SERVER_PORT should exit 1") | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.