docs(readme): add benchmark artifact references #10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Benchmark & Load Test | |
| on: | |
| workflow_dispatch: | |
| push: | |
| branches: [main] | |
| jobs: | |
| benchmark: | |
| name: Run Benchmarks | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| services: | |
| postgres: | |
| image: postgres:16-alpine | |
| env: | |
| POSTGRES_DB: journal | |
| POSTGRES_USER: journal | |
| POSTGRES_PASSWORD: journal | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 5s | |
| --health-timeout 5s | |
| --health-retries 10 | |
| redis: | |
| image: redis:7-alpine | |
| ports: | |
| - 6379:6379 | |
| options: >- | |
| --health-cmd "redis-cli ping" | |
| --health-interval 5s | |
| --health-timeout 5s | |
| --health-retries 10 | |
| env: | |
| DATABASE_URL: postgresql://journal:journal@localhost:5432/journal?sslmode=disable | |
| REDIS_URL: redis://localhost:6379/0 | |
| NATS_URL: nats://localhost:4222 | |
| PORT: "8080" | |
| PROMETHEUS_PORT: "2112" | |
| IDEMPOTENCY_TTL_HOURS: "24" | |
| OUTBOX_POLL_INTERVAL_MS: "500" | |
| OUTBOX_BATCH_SIZE: "100" | |
| MAX_SERIALIZATION_RETRIES: "3" | |
| SERIALIZATION_BACKOFF_BASE_MS: "10" | |
| LOG_LEVEL: "warn" | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Start NATS JetStream | |
| run: docker run -d -p 4222:4222 -p 8222:8222 --name nats nats:2.10-alpine -js | |
| - uses: actions/setup-go@v5 | |
| with: | |
| go-version: "1.22" | |
| cache: true | |
| # Install migrate CLI | |
| - name: Install migrate | |
| run: | | |
| curl -L https://github.com/golang-migrate/migrate/releases/download/v4.17.1/migrate.linux-amd64.tar.gz | tar xvz | |
| sudo mv migrate /usr/local/bin/ | |
| # Install k6 | |
| - name: Install k6 | |
| run: | | |
| curl -L https://github.com/grafana/k6/releases/download/v0.52.0/k6-v0.52.0-linux-amd64.tar.gz | tar xz | |
| sudo mv k6-v0.52.0-linux-amd64/k6 /usr/local/bin/ | |
| # Apply migrations | |
| - name: Run migrations | |
| run: migrate -path migrations -database "$DATABASE_URL" up | |
| # Unit + integration tests | |
| - name: Unit tests (with race detector) | |
| run: go test -race -cover -coverprofile=coverage.out ./internal/domain/... ./internal/ledger/... | |
| - name: Integration tests | |
| run: go test -race -v ./test/integration/... | |
| # Concurrency stress test | |
| - name: Concurrency stress test | |
| run: | | |
| go test -race -count=5 -timeout=300s -v ./test/concurrency/... \ | |
| 2>&1 | tee concurrency-results.txt | |
| # Start API for load testing | |
| - name: Build and start API | |
| run: | | |
| go build -o api ./cmd/api/... | |
| ./api & | |
| # Wait for API to be ready | |
| for i in $(seq 1 20); do | |
| if curl -sf http://localhost:8080/v1/health > /dev/null; then | |
| echo "API ready after ${i}s" | |
| break | |
| fi | |
| sleep 1 | |
| done | |
| # k6 Load tests | |
| - name: Baseline throughput (50 VUs, 60s) | |
| run: | | |
| k6 run \ | |
| --summary-trend-stats="med,p(95),p(99),max" \ | |
| --out json=baseline-results.json \ | |
| load/scenarios/baseline.js \ | |
| 2>&1 | tee baseline-summary.txt | |
| - name: Hot account contention (50 VUs, 60s) | |
| run: | | |
| k6 run \ | |
| --summary-trend-stats="med,p(95),p(99),max" \ | |
| --out json=hot-account-results.json \ | |
| load/scenarios/hot_account.js \ | |
| 2>&1 | tee hot-account-summary.txt | |
| - name: Idempotency storm (20 VUs, 60s) | |
| run: | | |
| k6 run \ | |
| --summary-trend-stats="med,p(95),p(99),max" \ | |
| --out json=idempotency-results.json \ | |
| load/scenarios/idempotency_storm.js \ | |
| 2>&1 | tee idempotency-summary.txt | |
| # Upload all results as artifacts | |
| - name: Upload benchmark results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: benchmark-results-${{ github.sha }} | |
| retention-days: 90 | |
| path: | | |
| coverage.out | |
| concurrency-results.txt | |
| baseline-summary.txt | |
| baseline-results.json | |
| hot-account-summary.txt | |
| hot-account-results.json | |
| idempotency-summary.txt | |
| idempotency-results.json | |
| # Print summary to job log | |
| - name: Print benchmark summary | |
| if: always() | |
| run: | | |
| echo "=== BASELINE ===" && cat baseline-summary.txt || true | |
| echo "=== HOT ACCOUNT ===" && cat hot-account-summary.txt || true | |
| echo "=== IDEMPOTENCY ===" && cat idempotency-summary.txt || true | |
| echo "=== CONCURRENCY ===" && cat concurrency-results.txt || true |