Skip to content

l4proxy: add active HTTP health checks#423

Open
tannevaled wants to merge 2 commits into
mholt:masterfrom
tannevaled:feat/active-http-health-check
Open

l4proxy: add active HTTP health checks#423
tannevaled wants to merge 2 commits into
mholt:masterfrom
tannevaled:feat/active-http-health-check

Conversation

@tannevaled

Copy link
Copy Markdown

What

Adds an optional HTTP mode to the layer4 proxy's active health checks. Today the active health check only performs a raw TCP dial, so it can tell whether a port is open but nothing about the application-level state behind it.

New ActiveHealthChecks fields (JSON):

  • uri — request path; when set, the check performs an HTTP GET instead of a TCP dial
  • expect_status — healthy status code, or a class (e.g. 2 matches any 2xx); default 200
  • https — perform the check over TLS
  • tls_skip_verify — skip TLS verification (useful with self-signed certs)

Caddyfile equivalents: health_uri, health_status (accepts 200 or 2xx), health_https, health_tls_skip_verify.

When uri is unset the check stays a raw TCP dial, so existing behavior is unchanged.

Why

It lets a layer4 proxy follow an application-level signal instead of mere port-liveness. For example, Patroni (PostgreSQL HA) exposes /primary, which returns 200 only on the elected leader; with this change the proxy can route to whichever upstream is currently primary and follow failover automatically — something the TCP-only check cannot do, since every node accepts TCP connections regardless of role.

Tests

Added healthchecks_test.go: healthy/unhealthy by status, status-class match, HTTPS (self-signed), connection-refused, invalid-URI, and Caddyfile parsing (happy + error paths). go test ./modules/l4proxy/ passes; gofmt and go vet are clean.

The active health checker only performed a raw TCP dial, so it could not
distinguish application-level state behind an open port. Add optional HTTP
probing to ActiveHealthChecks:

  - uri:             request path; when set, the check does an HTTP GET
  - expect_status:   healthy status, or a class (e.g. 2 => any 2xx); default 200
  - https:           probe over TLS
  - tls_skip_verify: skip cert verification for HTTPS probes

Caddyfile equivalents: health_uri, health_status, health_https,
health_tls_skip_verify. When uri is unset the check remains a raw TCP dial,
so existing behavior is unchanged.

This lets a layer4 proxy follow a primary-election endpoint such as
Patroni's /primary, which returns 200 only on the elected leader.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Remove dead error-handling around setHealthy (it never returns an error),
  bringing doActiveHTTPHealthCheck to 100% statement coverage.
- Document health_uri / health_status / health_https / health_tls_skip_verify
  in docs/handlers/proxy.md.
- Add a caddyfile_adapt integration test for the HTTP health check options.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant