From 1b3d8da827165d599ea2f8867e48723d00eab00c Mon Sep 17 00:00:00 2001 From: Liangsheng Yin Date: Thu, 21 May 2026 01:13:37 -0700 Subject: [PATCH] cap API quota for runner-utilization / amd-ci-job-monitor (#25965) --- .github/workflows/amd-ci-job-monitor.yml | 16 +++++++++++++++- .github/workflows/runner-utilization.yml | 19 ++++++++++++++++++- scripts/ci/utils/query_job_status.py | 4 ++-- scripts/ci/utils/runner_utilization_report.py | 4 +++- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/.github/workflows/amd-ci-job-monitor.yml b/.github/workflows/amd-ci-job-monitor.yml index cbb8798b1..b1af9c41e 100644 --- a/.github/workflows/amd-ci-job-monitor.yml +++ b/.github/workflows/amd-ci-job-monitor.yml @@ -19,9 +19,21 @@ on: required: false type: string +# Bound the API cost when the same ref pushes repeatedly. See note in +# runner-utilization.yml for the original incident this guards against. +concurrency: + group: amd-ci-job-monitor-${{ github.ref }} + cancel-in-progress: true + jobs: fetch-actions-data: name: Fetch Actions Snapshot + # Skip fork PRs entirely, and require the `run-ci` label on same-repo PRs. + # schedule and workflow_dispatch always run. + if: >- + github.event_name != 'pull_request' || + (github.event.pull_request.head.repo.full_name == github.repository && + contains(github.event.pull_request.labels.*.name, 'run-ci')) runs-on: ubuntu-latest env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -49,10 +61,12 @@ jobs: - name: Fetch Actions data snapshot timeout-minutes: 30 run: | + # PR-trigger is just a script smoke check; scan a 20-minute window + # (0.34h) to bound API cost. schedule / dispatch run the full report. python scripts/ci/utils/query_job_status.py \ --repo ${{ github.repository }} \ --workflow "${{ steps.select-workflows.outputs.workflows }}" \ - --hours ${{ inputs.hours || '24' }} \ + --hours ${{ (github.event_name == 'pull_request' && '0.34') || inputs.hours || '24' }} \ --dump-data-file actions-job-snapshot.json - name: Upload Actions data snapshot diff --git a/.github/workflows/runner-utilization.yml b/.github/workflows/runner-utilization.yml index 7c37e41de..b54306a87 100644 --- a/.github/workflows/runner-utilization.yml +++ b/.github/workflows/runner-utilization.yml @@ -19,9 +19,24 @@ on: required: false type: string +# Sandbox PRs (e.g. tom/kv_canary) push dozens of times in a row. Without this +# group, every push spawns another 24h API scan that races the previous ones +# and drains the shared 15k/hr installation token quota. Cancel-in-progress +# keeps at most one Runner Utilization run per ref alive at a time. +concurrency: + group: runner-utilization-${{ github.ref }} + cancel-in-progress: true + jobs: report: name: Generate Report + # Skip fork PRs entirely, and require the `run-ci` label on same-repo PRs + # so unlabeled iteration pushes (e.g. long-lived sandbox branches) don't + # fire the 24h API scan. schedule and workflow_dispatch always run. + if: >- + github.event_name != 'pull_request' || + (github.event.pull_request.head.repo.full_name == github.repository && + contains(github.event.pull_request.labels.*.name, 'run-ci')) runs-on: ubuntu-latest steps: - name: Checkout code @@ -37,7 +52,9 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | + # PR-trigger is just a script smoke check; scan a 20-minute window + # (0.34h) to bound API cost. schedule / dispatch run the full report. python scripts/ci/utils/runner_utilization_report.py \ --repo ${{ github.repository }} \ - --hours ${{ inputs.hours || '24' }} \ + --hours ${{ (github.event_name == 'pull_request' && '0.34') || inputs.hours || '24' }} \ ${{ inputs.filter && format('--filter {0}', inputs.filter) || '' }} diff --git a/scripts/ci/utils/query_job_status.py b/scripts/ci/utils/query_job_status.py index eb2910404..1aaca4555 100755 --- a/scripts/ci/utils/query_job_status.py +++ b/scripts/ci/utils/query_job_status.py @@ -1724,9 +1724,9 @@ def main(): ) parser.add_argument( "--hours", - type=int, + type=float, default=24, - help="Time window in hours (default: 24)", + help="Time window in hours (fractional ok, default: 24)", ) parser.add_argument( "--status", diff --git a/scripts/ci/utils/runner_utilization_report.py b/scripts/ci/utils/runner_utilization_report.py index 2792ea2a5..5e68d651c 100755 --- a/scripts/ci/utils/runner_utilization_report.py +++ b/scripts/ci/utils/runner_utilization_report.py @@ -599,7 +599,9 @@ def format_report( def main(): parser = argparse.ArgumentParser(description="Generate runner utilization report") parser.add_argument("--repo", default="sgl-project/sglang", help="GitHub repo") - parser.add_argument("--hours", type=int, default=24, help="Time window in hours") + parser.add_argument( + "--hours", type=float, default=24, help="Time window in hours (fractional ok)" + ) parser.add_argument( "--filter", type=str, help="Filter runner labels (e.g., '5090', 'h200')" )