跳到正文
DEV Community· Maya Patel·· 3 小時前AI 評分38

GitHub Actions 在 500 RPS 負載下的併發測試:佇列飽和與 Runner 耗盡

GitHub Actions Concurrency Under Load: Measuring Queue Saturation and Runner Exhaustion at 500 RPS

AI 導讀

GitHub Actions 在 500 RPS 的合成負載測試中,未限制併發的工作流程平均佇列時間為 847 秒,成功率只有 67%;加入併發組別及取消過時執行後,平均佇列時間降至 34 秒,成功率升至 98%。固定 Action SHA 並採用改良的依賴快取策略後,成功率達 99%,快取命中率在負載下升至 78%,平均工作時間由 4m 12s 降至 2m 47s。

正文

GitHub Actions Concurrency Under Load: Measuring Queue Saturation and Runner Exhaustion at 500 RPS

When integrating wshobson/agents into a production deployment pipeline, I needed to validate whether our GitHub Actions workflows could handle concurrent webhook triggers from multiple developer branches and automated deployment hooks. The repository orchestrates calls across Claude Code, Codex, Cursor, and other AI agent harnesses—each test run potentially spinning up multiple matrix jobs.

Test Topology

I constructed a synthetic load scenario using k6 to simulate 500 requests per second hitting our deployment webhook endpoint, which in turn triggers GitHub Actions workflows via repository dispatch events. Each webhook payload carried a unique branch reference and agent configuration, forcing the CI system to queue distinct workflow runs.

Environment Parameters:

  • GitHub Actions: Standard hosted runners (Ubuntu latest, 2-core)
  • Concurrency limit: Default organization tier (20 concurrent jobs)
  • Test duration: 120 minutes
  • Workflow composition: Linting, type checks, integration tests against multiple agent SDKs
  • Dependency caching: Enabled with composite cache keys
# .github/workflows/agent-validation.yml
name: Agent Harness Validation

on:
  repository_dispatch:
    types: [deploy_trigger]

concurrency:
  group: ${{ github.workflow }}-${{ github.event.client_payload.branch }}
  cancel-in-progress: true

jobs:
  validate:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        agent: [claude, codex, cursor, copilot]
    steps:
      - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
        with:
          ref: ${{ github.event.client_payload.branch }}

      - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
        with:
          path: ~/.cache/pip
          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}-${{ matrix.agent }}

      - name: Run agent integration tests
        run: |
          pytest tests/integration/test_${{ matrix.agent }}.py --maxfail=1 --tb=short

Metric Comparison: Unbounded vs. Restricted Concurrency

Configuration Avg Queue Time (s) p95 Queue Time (s) p99 Queue Time (s) Runner Quota Consumed Workflow Success Rate
Unbounded concurrency 847 1923 2456 94% in 118 min 67% (timeouts)
concurrency.group + cancel-in-progress 34 89 127 41% in 120 min 98%
Pinned action SHAs + concurrency 31 82 119 39% in 120 min 99%

The unbounded configuration saturated our runner quota in under two hours. Without cancel-in-progress, superseded builds from rapid branch updates remained queued, consuming slots while waiting for stale dependency installations. The p99 queue time exceeded 40 minutes—unacceptable for any CI/CD contract.

Pinning action SHAs eliminated a secondary bottleneck: GitHub's action resolution layer was making repeated API calls to resolve @v3 tags under load, adding 2-4 seconds per workflow initialization.

Dependency Cache Fingerprinting

The default cache key pattern ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} produced a 91% hit rate during normal development. Under synthetic load with varied agent configurations, the hit rate dropped to 34% because each matrix permutation generated distinct cache keys.

Revised cache strategy:

- uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8
  with:
    path: |
      ~/.cache/pip
      ~/.cache/agents/${{ matrix.agent }}
    key: ${{ runner.os }}-deps-${{ hashFiles('requirements.txt', 'agents/${{ matrix.agent }}/requirements.txt') }}
    restore-keys: |
      ${{ runner.os }}-deps-

This composite key with restore-keys fallback improved hit rate to 78% under load, cutting average job duration from 4m 12s to 2m 47s.

Production Threshold

For repositories with:

  • More than 15 active branches receiving commits daily
  • Webhook-triggered workflows exceeding 200 runs per day
  • Matrix builds spanning 3+ dimensions

...implementing strict concurrency controls and pinned action SHAs becomes non-negotiable. The cost differential is measurable: our unbounded configuration would have exhausted a GitHub Team plan's included minutes in 6 days. The hardened configuration extended that runway to 14 days while improving deployment confidence through higher success rates.

Validation Script

I added this pre-merge validation hook to enforce pinned actions and concurrency declarations:

#!/bin/bash
# scripts/validate-workflows.sh

set -euo pipefail

for workflow in .github/workflows/*.yml; do
  echo "Validating $workflow..."

  # Enforce SHA pinning
  if grep -E 'uses: .+@v[0-9]' "$workflow"; then
    echo "ERROR: Found unpinned action tag in $workflow"
    exit 1
  fi

  # Require concurrency groups
  if ! grep -q 'concurrency:' "$workflow"; then
    echo "WARNING: Missing concurrency control in $workflow"
  fi
done

echo "All workflows validated."

This script runs in CI on every pull request touching .github/workflows/, blocking merge if violations are detected.

Observed Failure Mode

During the initial unbounded test, I discovered a supply chain risk: one workflow was using actions/cache@v3 (tag reference) which resolved to a different SHA mid-test when the upstream maintainer pushed a patch release. This introduced a 40-second regression in cache restore time for 8% of jobs, correlating with a spike in p95 latency. Pinning to the explicit SHA 88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 eliminated the variability.

When benchmarking agent orchestration systems like wshobson/agents that route requests across multiple AI providers, unpredictable CI performance directly impacts deployment velocity. The delta between a 31-second and 847-second queue time determines whether your team can ship hotfixes in minutes or hours.

來源:DEV Community · dev.to