From a0aa22c80b6043de0c3033ab1569a8be39bc4ff1 Mon Sep 17 00:00:00 2001 From: Niek Otten Date: Thu, 25 Jun 2026 09:03:37 +0200 Subject: [PATCH] fix(infra): smoke waits on durable services, not the whole project (refs #30) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run 28 got the full stack healthy but `compose-smoke` still failed. The last compose line before the error was: container infra-flowable-init-1 exited (0) `docker compose up --wait` treats a service that exits as a failure of the "stay running" condition unless something depends on it via `service_completed_successfully`. oz-init/nrc-init are fine (openzaak/nrc-web depend on them), but flowable-init deploys the BPMN and exits 0 with no dependant, so whole-project `--wait` failed the instant it finished — even though everything else was healthy and nrc-init now exits 0. Smoke now: 1. `up -d` starts the full stack (one-shots run + deploy as before), then 2. `up -d --wait ` waits only for the durable health-checked services (openzaak nrc-web acl bff). Also drops the external `curl localhost:8080/health`: the containerized CI runner can't reach published host ports at localhost, and each service's healthcheck already runs inside its container — so `--wait` succeeding IS the smoke. Documented in docs/runbooks/gitea-actions-gotchas.md. Co-Authored-By: Claude Opus 4.8 (1M context) --- Makefile | 17 +++++++++++++---- docs/runbooks/ci.md | 2 +- docs/runbooks/gitea-actions-gotchas.md | 24 ++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 859716c..4606bb1 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,11 @@ SLN := register-referentie.slnx COMPOSE := infra/docker-compose.yml -HEALTH_URL := http://localhost:8080/health +# Long-running services with a healthcheck — the smoke waits on these. One-shot +# init jobs (oz-init, nrc-init, flowable-init) are NOT listed: `--wait` fails when +# a one-shot with no `service_completed_successfully` dependant exits (flowable-init), +# so we wait on the durable services instead. See docs/runbooks/gitea-actions-gotchas.md. +WAIT_SVCS := openzaak nrc-web acl bff OZ_COMPOSE := infra/openzaak/docker-compose.yml OZ_BASE := http://localhost:8000 NRC_COMPOSE := infra/opennotificaties/docker-compose.yml @@ -45,10 +49,15 @@ build: unit: dotnet test $(SLN) -c Release -## smoke: compose up (wait for healthy), curl /health, then tear down +## smoke: bring the whole stack up, wait for the health-checked services, tear down +# Step 1 starts EVERYTHING (incl. one-shot init jobs that deploy and exit 0). +# Step 2 waits only for the durable, health-checked services ($(WAIT_SVCS)) — see +# WAIT_SVCS above for why the one-shots are excluded. The healthchecks run inside +# the containers, so this needs no host port access (the CI runner can't reach +# published ports anyway). smoke: - docker compose -f $(COMPOSE) up -d --build --wait --wait-timeout 420 - bash -c 'curl -fsS $(HEALTH_URL); rc=$$?; docker compose -f $(COMPOSE) down --volumes; exit $$rc' + docker compose -f $(COMPOSE) up -d --build + bash -c 'docker compose -f $(COMPOSE) up -d --wait --wait-timeout 420 $(WAIT_SVCS); rc=$$?; docker compose -f $(COMPOSE) down --volumes; exit $$rc' ## down: stop and remove the local stack down: diff --git a/docs/runbooks/ci.md b/docs/runbooks/ci.md index 6432cc6..107b985 100644 --- a/docs/runbooks/ci.md +++ b/docs/runbooks/ci.md @@ -16,7 +16,7 @@ and CI cannot drift: | `lint` | `make lint` → `dotnet format … --verify-no-changes` | .NET 10 SDK | | `build` | `make build` → `dotnet build … -c Release` | .NET 10 SDK | | `unit` | `make unit` → `dotnet test … -c Release` | .NET 10 SDK | -| `compose-smoke` | `make smoke` → compose up `--wait` → `curl /health` → `down` | container engine + compose v2 | +| `compose-smoke` | `make smoke` → `up -d` (full stack) → `up --wait` durable services → `down` | container engine + compose v2 | All `uses:` references are absolute, tag-pinned URLs (`https://github.com/actions/checkout@v4`, `https://github.com/actions/setup-dotnet@v4`) per CLAUDE.md §8.7 and §15 — Gitea diff --git a/docs/runbooks/gitea-actions-gotchas.md b/docs/runbooks/gitea-actions-gotchas.md index ebe6834..280c682 100644 --- a/docs/runbooks/gitea-actions-gotchas.md +++ b/docs/runbooks/gitea-actions-gotchas.md @@ -66,6 +66,30 @@ so the SELinux `:z`/`:Z` relabel flag is no longer needed anywhere in `infra/`, and rootless Podman no longer needs the files to be world-readable. One mechanism (build) works on both Podman locally and Docker-in-Docker in CI. +## `--wait` fails on one-shot containers with no dependant + +`docker compose up --wait` treats a service that **exits** as a failure of the +"stay up" condition — **unless** another service depends on it with +`condition: service_completed_successfully`. Our init jobs `oz-init` and +`nrc-init` are fine (`openzaak`/`nrc-web` depend on their completion), but +`flowable-init` deploys the BPMN and exits 0 with **no dependant**, so a +whole-project `--wait` fails the moment it exits — even with everything else +healthy. The symptom is a `compose-smoke` failure whose last compose line is: + +``` +container infra-flowable-init-1 exited (0) +``` + +**Fix.** The smoke does **not** `--wait` on the whole project. It starts +everything with `up -d`, then `up -d --wait ` only for the durable, +health-checked services (`openzaak nrc-web acl bff` — see `WAIT_SVCS` in the +`Makefile`). One-shots still run (and deploy), they just don't gate `--wait`. + +This also removed the old external `curl http://localhost:8080/health` check: +the CI job runs in a container and **can't reach published host ports** at +`localhost`, and the per-service healthchecks (which run *inside* the +containers) already prove readiness, so `--wait` succeeding *is* the smoke. + ## `--wait` needs an explicit timeout `docker compose up --wait` defaults to a 60-second timeout in some Compose v2