veza/.github/workflows/loadtest.yml
senke 8fc08935ab fix(ci): migrate .github/workflows to self-hosted runner + gate heavy workflows
The forgejo-runner on srv-102v advertises labels `incus:host,self-hosted:host`,
so jobs pinned to `ubuntu-latest` matched no runner and exited in 0s.

- ci.yml / security-scan.yml / trivy-fs.yml: runs-on → [self-hosted, incus]
- e2e.yml / go-fuzz.yml / loadtest.yml: same migration AND gate triggers to
  workflow_dispatch only (push/pull_request/schedule commented out) — single
  self-hosted runner, heavy suites would block the queue.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 00:08:38 +02:00

126 lines
5.3 KiB
YAML

name: k6 nightly load test
# v1.0.9 W4 Day 20 — runs the mixed-scenarios k6 script against the
# staging environment every night at 02:30 UTC. The acceptance gate
# is "pass green 3 nuits consécutives" before flipping a release —
# the artifact uploaded by this workflow carries the JSON summary
# the operator inspects.
#
# Scope deliberately narrow : runs ONLY on staging, NEVER on prod.
# A separate manually-triggered workflow (workflow_dispatch) covers
# pre-launch capacity drills with a longer ramp.
on:
# GATED — k6 hammer is too heavy for the single self-hosted runner.
# Re-enable the cron once a dedicated load-test runner exists.
# schedule:
# - cron: "30 2 * * *"
workflow_dispatch:
inputs:
duration:
description: "Duration per scenario (e.g. 5m, 15m, 1h)"
required: false
default: "5m"
type: string
base_url:
description: "Override staging URL"
required: false
default: ""
type: string
env:
GIT_SSL_NO_VERIFY: "true"
# Defaults — override via workflow_dispatch input or repo vars.
DEFAULT_BASE_URL: "https://staging.veza.fr"
jobs:
loadtest:
name: k6 mixed scenarios (1650 VU steady)
runs-on: [self-hosted, incus]
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install k6
run: |
set -euo pipefail
sudo gpg -k
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg \
--keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" \
| sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install -y k6
k6 version
- name: Resolve test inputs
id: inputs
run: |
set -euo pipefail
BASE_URL="${{ github.event.inputs.base_url }}"
if [ -z "$BASE_URL" ]; then
BASE_URL="${{ vars.STAGING_BASE_URL || env.DEFAULT_BASE_URL }}"
fi
DURATION="${{ github.event.inputs.duration }}"
if [ -z "$DURATION" ]; then
DURATION="5m"
fi
echo "base_url=$BASE_URL" >> "$GITHUB_OUTPUT"
echo "duration=$DURATION" >> "$GITHUB_OUTPUT"
- name: Pre-flight — staging is reachable
run: |
set -euo pipefail
url="${{ steps.inputs.outputs.base_url }}/api/v1/health"
echo "::notice::Pre-flight GET $url"
status=$(curl -k -sS --max-time 10 -o /dev/null -w "%{http_code}" "$url" || echo "000")
if [ "$status" != "200" ]; then
echo "::error::Staging /health returned $status — aborting load test."
exit 1
fi
- name: Run k6 mixed scenarios
id: run
env:
BASE_URL: ${{ steps.inputs.outputs.base_url }}
DURATION: ${{ steps.inputs.outputs.duration }}
USER_TOKEN: ${{ secrets.STAGING_LOADTEST_TOKEN }}
STREAM_TRACK_ID: ${{ vars.STAGING_LOADTEST_TRACK_ID || '00000000-0000-0000-0000-000000000001' }}
run: |
set -euo pipefail
if [ -z "$USER_TOKEN" ]; then
echo "::warning::STAGING_LOADTEST_TOKEN secret is empty — auth-required scenarios will record 401s as errors."
fi
k6 run --quiet \
--summary-export=k6-summary.json \
scripts/loadtest/k6_mixed_scenarios.js
- name: Upload k6 summary artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: k6-summary-${{ github.run_number }}
path: |
k6-summary.json
scripts/loadtest/k6_mixed_scenarios.js
retention-days: 30
- name: Annotate thresholds in summary
if: always()
run: |
set -euo pipefail
if [ ! -f k6-summary.json ]; then
echo "::warning::No summary artifact — k6 likely failed before write."
exit 0
fi
echo "## k6 load test summary" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
jq -r '
(.metrics.http_reqs.values.count // 0) as $reqs
| (.metrics.http_req_failed.values.rate // 0) as $err
| (.metrics.http_req_duration.values["p(95)"] // 0) as $p95
| (.metrics.http_req_duration.values["p(99)"] // 0) as $p99
| "- requests: \($reqs)\n- failed rate: \($err * 100 | round)/100 %\n- p95: \($p95 | round) ms\n- p99: \($p99 | round) ms"
' k6-summary.json >> "$GITHUB_STEP_SUMMARY"