feat(woodpecker): liveness probe on the agent healthcheck #705

Merged
k.renner merged 1 commits from woodpecker-agent-probe into master 2026-08-28 12:33:21 +00:00
Member

Der letzte Workload im Repo, der einen echten Dienst fährt und keinerlei Probe hatte.

WOODPECKER_HEALTHCHECK steht per Default auf true und bedient bereits :3000 — es musste also nichts aktiviert werden, der Port war nur nie deklariert und nie geprüft. Am laufenden Pod bestätigt: /healthz antwortet 200, / und /metrics nicht.

Was die Probe wirklich prüft — enger als der Name verspricht

Und enger, als ich angenommen hatte, als ich sie vorgeschlagen habe. Aus agent/state.go:

func (s *State) Healthy() bool {
    now := time.Now()
    buf := time.Hour // 1 hour buffer
    for _, item := range s.Metadata {
        if now.After(item.Started.Add(item.Timeout).Add(buf)) {
            return false
        }
    }
    return true
}

/healthz liefert 500 nur dann, wenn ein laufender Workflow seine eigene Timeout-Zeit plus eine Stunde Puffer überschritten hat. Ein Agent ohne Arbeit antwortet immer 200.

Fängt Fängt nicht
einen festgefahrenen Build, der einen Slot blockiert — heute völlig unsichtbar einen Agenten, der die Serververbindung verloren hat

Der zweite Fall war meine ursprüngliche Begründung im Survey („ein hängender Agent nimmt still keine Builds mehr an") — die war falsch. Ein solcher Agent meldet sich weiterhin gesund. Das steht jetzt im Kommentar, weil eine grüne Probe hier leicht als „CI ist in Ordnung" gelesen wird.

Nur Liveness

Der Agent steht hinter keinem Service, eine Readiness-Probe würde also nichts steuern. Die Schwellwerte sind kurz, weil die Upstream-Bedingung ohnehin eine Stunde Puffer mitbringt.

Damit ist der Survey abgeschlossen

Was jetzt noch ohne Probe läuft, ist entweder fremdverwaltet — Rook (24), die authentik-Outposts (11), die kube-prometheus-stack-/Grafana-/Loki-Sidecars (7), Multus und CNI (5), cert-manager-cainjector, mariadb-operator, velero node-agent — oder eine Sidecar-Schleife ohne lauschenden Socket, wo eine exec-Probe kaum mehr behaupten würde als der Container-Exit ohnehin schon leistet: config-sync, die zwei socat-Relays, discovery-guard, interview-watch, sidekiq.

Dazu die zwei bereits dokumentierten Ausnahmen: bridge-tls-proxy (socat auf 127.0.0.1, für das kubelet nicht erreichbar) und protonmail-bridge (darf während der Re-Authentifizierung offline sein).

Geprüft

Mit Flux' Field-Manager dry-run-appliziert: serverside-applied.

Nach dem Merge prüfe ich Ready und 0 Restarts — bei einer Liveness-Probe auf einem CI-Agenten wäre ein Fehlalarm besonders teuer, weil ein Restart alle laufenden Workflows mitnimmt.

Der letzte Workload im Repo, der einen echten Dienst fährt und keinerlei Probe hatte. `WOODPECKER_HEALTHCHECK` steht per Default auf `true` und bedient bereits `:3000` — es musste also nichts aktiviert werden, der Port war nur nie deklariert und nie geprüft. Am laufenden Pod bestätigt: `/healthz` antwortet 200, `/` und `/metrics` nicht. ## Was die Probe wirklich prüft — enger als der Name verspricht Und enger, als **ich** angenommen hatte, als ich sie vorgeschlagen habe. Aus `agent/state.go`: ```go func (s *State) Healthy() bool { now := time.Now() buf := time.Hour // 1 hour buffer for _, item := range s.Metadata { if now.After(item.Started.Add(item.Timeout).Add(buf)) { return false } } return true } ``` `/healthz` liefert **500 nur dann**, wenn ein laufender Workflow seine eigene Timeout-Zeit **plus eine Stunde Puffer** überschritten hat. Ein Agent ohne Arbeit antwortet **immer** 200. | Fängt | Fängt nicht | |---|---| | einen festgefahrenen Build, der einen Slot blockiert — heute völlig unsichtbar | einen Agenten, der die Serververbindung verloren hat | Der zweite Fall war meine ursprüngliche Begründung im Survey („ein hängender Agent nimmt still keine Builds mehr an") — **die war falsch**. Ein solcher Agent meldet sich weiterhin gesund. Das steht jetzt im Kommentar, weil eine grüne Probe hier leicht als „CI ist in Ordnung" gelesen wird. ## Nur Liveness Der Agent steht hinter keinem Service, eine Readiness-Probe würde also nichts steuern. Die Schwellwerte sind kurz, weil die Upstream-Bedingung ohnehin eine Stunde Puffer mitbringt. ## Damit ist der Survey abgeschlossen Was jetzt noch ohne Probe läuft, ist entweder **fremdverwaltet** — Rook (24), die authentik-Outposts (11), die kube-prometheus-stack-/Grafana-/Loki-Sidecars (7), Multus und CNI (5), cert-manager-cainjector, mariadb-operator, velero node-agent — oder eine **Sidecar-Schleife ohne lauschenden Socket**, wo eine `exec`-Probe kaum mehr behaupten würde als der Container-Exit ohnehin schon leistet: `config-sync`, die zwei `socat`-Relays, `discovery-guard`, `interview-watch`, `sidekiq`. Dazu die zwei bereits dokumentierten Ausnahmen: `bridge-tls-proxy` (socat auf `127.0.0.1`, für das kubelet nicht erreichbar) und `protonmail-bridge` (darf während der Re-Authentifizierung offline sein). ## Geprüft Mit Flux' Field-Manager dry-run-appliziert: `serverside-applied`. Nach dem Merge prüfe ich `Ready` **und 0 Restarts** — bei einer Liveness-Probe auf einem CI-Agenten wäre ein Fehlalarm besonders teuer, weil ein Restart alle laufenden Workflows mitnimmt.
claude-bot added 1 commit 2026-08-28 12:32:12 +00:00
feat(woodpecker): liveness probe on the agent healthcheck
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline was successful
1f3afcd7e3
The agent was the last workload in this repo running a real service with no
probe of any kind. WOODPECKER_HEALTHCHECK defaults to true and already serves
:3000, so nothing had to be enabled — the port was simply never declared and
never probed. Confirmed against the running pod: /healthz answers 200, / and
/metrics do not.

What it actually asserts is narrower than the name suggests, and narrower than
I assumed when proposing this. State.Healthy in agent/state.go returns false
only when a running workflow has passed its own timeout plus a one-hour buffer;
an agent with nothing to do always answers 200.

So this catches one specific failure — a wedged build holding a slot, which
today nobody would notice — and explicitly does not catch an agent that has
lost its connection to the server. That agent reports healthy while quietly
taking no work, which was the failure I originally wanted to cover. The comment
says so, because a green probe here is easy to misread as "CI is fine".

Liveness only. The agent fronts no Service, so a readiness probe would gate
nothing. Thresholds are short because the upstream condition already carries an
hour of debounce.

Everything else still unprobed is either operator- or chart-owned (Rook, the
authentik outposts, the kube-prometheus-stack sidecars, Multus, cert-manager,
mariadb-operator, velero node-agent) or a sidecar loop with no listening socket
where an exec probe would assert little beyond what container exit already
does.
k.renner merged commit e205f58b87 into master 2026-08-28 12:33:21 +00:00
review-bot left a comment
Member

🤖 Automated review — model claude-haiku-4-5-20251001 (complexity: trivial), commit 1f3afcd7e37689281963be3d21877519206e42e0.

Advisory review by the review-bot pipeline. It never approves; a human merges. Push new commits to get a fresh review.


Summary

This PR adds a liveness probe to the Woodpecker agent deployment, declaring port 3000 and configuring an HTTP healthcheck on /healthz. The change is well-documented and correctly configured. No blocking issues.

🟢 Nits

The probe configuration looks solid with reasonable thresholds. The extensive documentation in the comments (lines 103–114) appropriately manages expectations by clearly stating what the probe catches (wedged builds holding a slot) and what it doesn't (lost server connections). This prevents future maintainers from misinterpreting a green probe as "CI is fine."

Port declaration (name health, containerPort 3000) is correct and follows the pattern used in server.yaml which also probes /healthz on port 8000.

Probe thresholds are sensible:

  • initialDelaySeconds: 20 gives the agent time to start
  • periodSeconds: 30 is reasonable for a liveness check over a 1-hour timeout buffer
  • timeoutSeconds: 5 is appropriate for a simple HTTP GET
  • failureThreshold defaults to 3 (90 seconds of consecutive failures before restart), which matches the upstream's 1-hour debounce

Tests

This is a Kubernetes manifest change with no application code to test. The PR author notes they will verify Ready status and 0 Restarts post-merge, which is the right approach for a liveness probe on a CI agent (false positives are expensive—a restart cancels all running workflows).

Recommendation

Looks reasonable — no blocking issues; comments above are optional.

🤖 **Automated review** — model `claude-haiku-4-5-20251001` (complexity: trivial), commit `1f3afcd7e37689281963be3d21877519206e42e0`. > Advisory review by the `review-bot` pipeline. It never approves; a human merges. Push new commits to get a fresh review. --- ## Summary This PR adds a liveness probe to the Woodpecker agent deployment, declaring port 3000 and configuring an HTTP healthcheck on `/healthz`. The change is well-documented and correctly configured. No blocking issues. ## 🟢 Nits The probe configuration looks solid with reasonable thresholds. The extensive documentation in the comments (lines 103–114) appropriately manages expectations by clearly stating what the probe catches (wedged builds holding a slot) and what it doesn't (lost server connections). This prevents future maintainers from misinterpreting a green probe as "CI is fine." Port declaration (name `health`, containerPort 3000) is correct and follows the pattern used in `server.yaml` which also probes `/healthz` on port 8000. Probe thresholds are sensible: - `initialDelaySeconds: 20` gives the agent time to start - `periodSeconds: 30` is reasonable for a liveness check over a 1-hour timeout buffer - `timeoutSeconds: 5` is appropriate for a simple HTTP GET - `failureThreshold` defaults to 3 (90 seconds of consecutive failures before restart), which matches the upstream's 1-hour debounce ## Tests This is a Kubernetes manifest change with no application code to test. The PR author notes they will verify `Ready` status and 0 Restarts post-merge, which is the right approach for a liveness probe on a CI agent (false positives are expensive—a restart cancels all running workflows). ## Recommendation Looks reasonable — no blocking issues; comments above are optional. <!-- pr-review:sha=1f3afcd7e37689281963be3d21877519206e42e0 -->
Sign in to join this conversation.