|
| 1 | +name: zz-watchdog-probe |
| 2 | +permissions: |
| 3 | + actions: write |
| 4 | + |
| 5 | +# Once the month's macro runner minutes are spent, a job for the runner stays |
| 6 | +# queued (it never fails or skips) until GitHub drops it after 24 hours, and |
| 7 | +# holds the codspeed-macro concurrency group all that time. This workflow, on a |
| 8 | +# standard runner, cancels every run of a macro workflow whose job has waited |
| 9 | +# for a runner longer than QUEUED_LIMIT_MINUTES, and says so in its summary. |
| 10 | + |
| 11 | +on: |
| 12 | + schedule: |
| 13 | + - cron: "*/15 * * * *" |
| 14 | + workflow_dispatch: |
| 15 | + # TEMPORARY: the watchdog check (removed before review). |
| 16 | + push: |
| 17 | + branches: ["farhan/affectionate-dijkstra-dg3cgo"] |
| 18 | + paths: |
| 19 | + - ".github/workflows/zz_watchdog_probe.yml" |
| 20 | + |
| 21 | +concurrency: |
| 22 | + group: zz-watchdog-probe |
| 23 | + cancel-in-progress: true |
| 24 | + |
| 25 | +env: |
| 26 | + QUEUED_LIMIT_MINUTES: 5 |
| 27 | + # Every workflow with a job in the codspeed-macro concurrency group. |
| 28 | + MACRO_WORKFLOWS: zz_watchdog_probe_queued.yml |
| 29 | + |
| 30 | +defaults: |
| 31 | + run: |
| 32 | + shell: bash |
| 33 | + |
| 34 | +jobs: |
| 35 | + watchdog: |
| 36 | + name: watchdog |
| 37 | + timeout-minutes: 5 |
| 38 | + runs-on: ubuntu-latest |
| 39 | + steps: |
| 40 | + - name: Cancel macro runs no runner picked up |
| 41 | + env: |
| 42 | + GH_TOKEN: ${{ github.token }} |
| 43 | + GH_REPO: ${{ github.repository }} |
| 44 | + run: | |
| 45 | + set -euo pipefail |
| 46 | + limit=$((QUEUED_LIMIT_MINUTES * 60)) |
| 47 | + now=$(date -u +%s) |
| 48 | + cancelled=0 |
| 49 | + for workflow in $MACRO_WORKFLOWS; do |
| 50 | + for status in queued in_progress; do |
| 51 | + runs=$(gh api "repos/$GH_REPO/actions/workflows/$workflow/runs?status=$status&per_page=100" --jq '.workflow_runs[] | "\(.id) \(.html_url)"') |
| 52 | + while read -r run url; do |
| 53 | + [ -n "$run" ] || continue |
| 54 | + # A job waiting for a runner: queued and not assigned to one. |
| 55 | + waiting_since=$(gh api "repos/$GH_REPO/actions/runs/$run/jobs" --jq '[.jobs[] | select(.status == "queued" and ((.runner_name // "") == "")) | .created_at] | min // empty') |
| 56 | + [ -n "$waiting_since" ] || continue |
| 57 | + waited=$((now - $(date -u -d "$waiting_since" +%s))) |
| 58 | + if [ "$waited" -gt "$limit" ]; then |
| 59 | + gh run cancel "$run" |
| 60 | + echo "- cancelled [$workflow run $run]($url): its job waited $((waited / 60)) min for a macro runner (limit $QUEUED_LIMIT_MINUTES min); the month's macro minutes are probably spent." | tee -a "$GITHUB_STEP_SUMMARY" |
| 61 | + cancelled=$((cancelled + 1)) |
| 62 | + fi |
| 63 | + done <<< "$runs" |
| 64 | + done |
| 65 | + done |
| 66 | + echo "$cancelled run(s) cancelled" | tee -a "$GITHUB_STEP_SUMMARY" |
0 commit comments