From 6771fccf47ed9fa7935bceadada1bea44c20b260 Mon Sep 17 00:00:00 2001 From: Niek Otten Date: Thu, 23 Jul 2026 15:18:16 +0000 Subject: [PATCH] ci: parallelise jobs at runner capacity >1, keep heavy jobs apart (closes #127) (#128) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What & why The runner's `capacity` was raised to 2. The six CI jobs have no `needs:` between them, so they already schedule concurrently now — this PR makes that safe and tidy rather than enabling it. - **Keep the two memory-heavy jobs apart.** `verify-stack` now `needs: [mutation]` — not a data dependency, but so Stryker and the full-stack-bring-up + Playwright browser never run at once on the one host and re-trigger the e2e OOM (#126, commit d5e5fa2). `if: ${{ !cancelled() }}` keeps verify-stack running even when the mutation ratchet fails, so we don't lose its signal, while still honouring cancellation. - **Light jobs stay dependency-free** (lint / build / unit / frontend) → they parallelise up to runner capacity. - **Supersede stale runs** via a workflow `concurrency` group, so a new push cancels the previous run and frees the slot instead of piling up. Net effect at capacity 2: the light jobs pair up (and overlap `mutation`), then `verify-stack` runs alone — shorter wall-clock, no heavy-heavy collision. Closes #127 ## Definition of Done - [x] Linked issue (#127). - [x] Conventional Commit referencing it. - [ ] CI green — this PR **is** the test: it exercises `needs`, `if: !cancelled()`, and the `concurrency` group on Gitea. Watch that (a) verify-stack starts only after mutation, (b) verify-stack still runs, (c) the workflow parses (concurrency accepted). - [x] No app/docs/ADR impact (CI-only). ## Notes for reviewers - **One thing to watch on this first run:** if this Gitea version doesn't support the top-level `concurrency` key, drop that hunk — the `needs`/`if` guard is the load-bearing part and is plain job-graph syntax. - **Cross-run collisions** (two different PRs' `verify-stack` on the 2-capacity runner) aren't controllable via intra-workflow `needs`. If that becomes a problem, the clean fix is a second runner (or a dedicated capacity-1 label for the stack job) rather than ordering — out of scope here. Reviewed-on: https://git.labs.respellion.tech/eho/register-referentie/pulls/128 --- .gitea/workflows/ci.yaml | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 4ec07a3..84e9f79 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -9,6 +9,12 @@ on: permissions: contents: read +# Supersede stale runs: a new push to the same branch/PR cancels the previous run, so the runner's +# concurrency slots aren't spent on commits nobody is waiting for (refs #127). +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + # Self-hosted runner — see docs/runbooks/ci.md for the runner setup. # `uses:` are absolute, tag-pinned URLs (CLAUDE.md §8.7 / §15). @@ -129,12 +135,20 @@ jobs: path: services/bff/StrykerOutput/**/reports/mutation-report.html if-no-files-found: warn - # One stage for every check that needs the live stack. On the single self-hosted - # runner jobs run sequentially, so booting OpenZaak once (instead of once per job) - # is the cheapest layout (issue #58). No setup-dotnet: the ACL test runs in a built - # image and everything reaches services by container IP. Needs Docker + egress + # One stage for every check that needs the live stack. Booting OpenZaak once (instead + # of once per job) is the cheapest layout (issue #58). No setup-dotnet: the ACL test runs + # in a built image and everything reaches services by container IP. Needs Docker + egress # (base images, nuget, selectielijst.openzaak.nl). + # + # `needs: [mutation]` is NOT a data dependency — it serialises the two memory-heavy jobs so + # they never co-schedule now the runner has capacity >1. A concurrent Stryker run + full-stack + # bring-up + Playwright browser on one host is what OOMs the e2e (commit d5e5fa2, #126). The + # light .NET/frontend jobs have no `needs`, so they still parallelise up to runner capacity. + # `if: !cancelled()` keeps verify-stack running even when the mutation ratchet fails (so we don't + # lose its signal) while still honouring run cancellation from the concurrency group above. verify-stack: + needs: [mutation] + if: ${{ !cancelled() }} runs-on: ubuntu-latest steps: - uses: https://github.com/actions/checkout@v4