-
Notifications
You must be signed in to change notification settings - Fork 0
87 lines (74 loc) · 3.31 KB
/
Copy pathdetect-infinite-loop.yml
File metadata and controls
87 lines (74 loc) · 3.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# -----------------------------------------------------------------------------------------
# GitHub Actions Workflow: Infinite Loop Detector
#
# Description:
# Periodically scans recent GitHub Actions workflow runs (every 5 minutes) to detect
# potential infinite execution loops in specified workflows. If the number of
# in-flight runs (started but not completed) for any workflow exceeds a configured
# threshold, this workflow cancels all non-completed runs to break the loop.
#
# Trigger:
# - Scheduled via cron every 5 minutes
#
# Monitored Workflows:
# - env-test.yml
# - promote.yml
# - deploy.yml
#
# Parameters:
# - MAX_LOOKBACK_MINUTES: Look-back window for detecting excessive runs (default: 10)
# - ALLOWED_IN_FLIGHT: Max number of in-flight runs allowed per workflow (default: 1)
#
# Behavior:
# - Uses GitHub API to count recent workflow runs by name within the lookback window.
# - Compares total started vs completed runs to infer in-flight count.
# - Cancels all non-completed runs if threshold is exceeded.
#
# Requirements:
# - Requires `GH_TOKEN` or `GH_PAT` secret with permissions to list and cancel runs.
# - Requires GitHub CLI (`gh`) to be available in the runner environment.
# -----------------------------------------------------------------------------------------
name: Infinite Loop Detector
on:
#schedule:
# - cron: '*/5 * * * *'
jobs:
detect-infinite-loop:
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
WORKFLOWS: "env-test.yml promote.yml deploy.yml"
MAX_LOOKBACK_MINUTES: 10
ALLOWED_IN_FLIGHT: 1
steps:
- name: Detect workflow loops per workflow
id: loop-check
run: |
set -euo pipefail
echo "⏱ Checking for loops within the last $MAX_LOOKBACK_MINUTES minutes..."
SINCE=$(date -u -d "$MAX_LOOKBACK_MINUTES minutes ago" +%Y-%m-%dT%H:%M:%SZ)
echo "Time window starts at: $SINCE"
SHOULD_CANCEL=0
for WF in $WORKFLOWS; do
echo "🔍 Checking workflow: $WF"
STARTED=$(gh api repos/${{ github.repository }}/actions/runs \
--jq '[.workflow_runs[] | select(.name == "'"$WF"'" and .created_at > "'"$SINCE"'")] | length')
COMPLETED=$(gh api repos/${{ github.repository }}/actions/runs \
--jq '[.workflow_runs[] | select(.name == "'"$WF"'" and .created_at > "'"$SINCE"'" and .status == "completed")] | length')
IN_FLIGHT=$((STARTED - COMPLETED))
echo " ➤ Started: $STARTED"
echo " ➤ Completed: $COMPLETED"
echo " ➤ In-flight: $IN_FLIGHT"
if (( IN_FLIGHT > ALLOWED_IN_FLIGHT )); then
echo " ⚠️ Detected possible loop: '$WF' has $IN_FLIGHT in-flight runs (allowed: $ALLOWED_IN_FLIGHT)"
SHOULD_CANCEL=1
fi
done
echo "cancel_flag=$SHOULD_CANCEL" >> "$GITHUB_OUTPUT"
- name: Cancel in-progress workflows if needed
if: ${{ steps.loop-check.outputs.cancel_flag == '1' }}
run: |
echo "🚨 Loop detected – cancelling in-progress workflow runs..."
gh api repos/${{ github.repository }}/actions/runs \
--jq '.workflow_runs[] | select(.status != "completed") | .id' | \
xargs -r -I{} gh api -X POST repos/${{ github.repository }}/actions/runs/{}/cancel