diff --git a/.github/actions/avoid-rate-limit/action.yml b/.github/actions/avoid-rate-limit/action.yml deleted file mode 100755 index 20029f86..00000000 --- a/.github/actions/avoid-rate-limit/action.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Avoid Rate Limit -description: Pause workflow to avoid hitting the rate limit -inputs: - sleep_time: - description: Duration in seconds to sleep - required: true -runs: - using: "composite" - steps: - - run: | - if [[ "${{ inputs.sleep_time }}" -eq 0 ]]; then - echo "Skip Pause ... Far from Rate Limit" - else - echo "${{ inputs.sleep_time }} Second Pause for Rate Limit" - sleep ${{ inputs.sleep_time }} - fi - shell: bash diff --git a/.github/actions/check-rate-limit/action.yml b/.github/actions/check-rate-limit/action.yml deleted file mode 100755 index 5cb8d27f..00000000 --- a/.github/actions/check-rate-limit/action.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: Check Rate Limit -description: Checks GitHub rate limits and dynamically calculates sleep times (accounts for secondary rate limits). -inputs: - token: - description: GitHub or PAT token. - required: true -outputs: - sleep_time: - description: Calculated sleep time in seconds. -runs: - using: "composite" - steps: - - run: | - TOKEN="${{ inputs.token }}" - SLEEP_TIME=0 - BASE_TIME=64 - MIN_TIME=$(( BASE_TIME * 2 )) - MAX_RETRIES=6 - RETRY_COUNT=0 - RATE_LIMIT_URL="https://api.github.com/rate_limit" - - calculate_sleep_time() { - RATE_LIMIT_DATA=$(curl -s -H "Authorization: Bearer $TOKEN" -H "Accept: application/vnd.github.v3+json" $RATE_LIMIT_URL) - REMAINING_CALLS=$(echo $RATE_LIMIT_DATA | jq -r '.core.remaining') - RESET_TIME=$(echo $RATE_LIMIT_DATA | jq -r '.core.reset') - CURRENT_TIME=$(date +%s) - WAIT_PERIOD=$(( RESET_TIME - CURRENT_TIME )) - - if (( REMAINING_CALLS > 9 )); then - SLEEP_TIME=0 - elif (( REMAINING_CALLS > 1 )); then - SLEEP_TIME=$(( WAIT_PERIOD / REMAINING_CALLS )) - else - SLEEP_TIME=$(( WAIT_PERIOD + 60 )) - fi - - # Ensure a minimum sleep time to mitigate secondary rate limits. - if (( SLEEP_TIME < MIN_TIME )); then - SLEEP_TIME=$MIN_TIME - fi - } - - handle_secondary_rate_limit() { - while (( RETRY_COUNT < MAX_RETRIES )); do - RESPONSE=$(curl -s -I -H "Authorization: Bearer $TOKEN" $RATE_LIMIT_URL) - RETRY_BASE=$(echo "$RESPONSE" | grep -i 'retry-after' | awk '{print $2}' | tr -d '\r') - - if [[ ! -n "$RETRY_BASE" ]]; then - break - fi - - if (( RETRY_BASE < BASE_TIME )); then - RETRY_BASE=$BASE_TIME - fi - - SCALE_FACTOR=$(( RETRY_COUNT + 1 )) - RETRY_AFTER=$(( RETRY_BASE * SCALE_FACTOR * SCALE_FACTOR )) - RETRY_COUNT=$SCALE_FACTOR - - echo "Secondary Rate Limit is Active" - echo "Wait $RETRY_AFTER seconds for reset..." - - sleep "$RETRY_AFTER" - - if (( RETRY_COUNT >= MAX_RETRIES )); then - break - fi - done - } - - # Check for secondary rate limits - handle_secondary_rate_limit - - # Calculate sleep time for primary rate limits - calculate_sleep_time - - echo "sleep_time=$SLEEP_TIME" >> $GITHUB_OUTPUT - shell: bash diff --git a/.github/actions/handle-rate-limits/action.yml b/.github/actions/handle-rate-limits/action.yml new file mode 100755 index 00000000..8a3037f0 --- /dev/null +++ b/.github/actions/handle-rate-limits/action.yml @@ -0,0 +1,112 @@ +name: Rate Limit Handler +description: Check rate limits and dynamically calculate/apply sleep times. +inputs: + token: + description: Personal Access Token (PAT) for GitHub API. + required: true +runs: + using: "composite" + steps: + - name: Handle Rate Limits + shell: bash + run: | + TOKEN="${{ inputs.token }}" + SLEEP_TIME=0 + BASE_TIME=64 + MAX_RETRIES=6 + RETRY_COUNT=0 + + calculate_sleep_time() { + RATE_LIMIT_DATA=$(curl -s --max-time 10 \ + -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/rate_limit) + printf "Rate Limit Response:\n%s\n" "$RATE_LIMIT_DATA" + + # Validate JSON response + if ! echo "$RATE_LIMIT_DATA" | jq -e '.' > /dev/null 2>&1; then + SLEEP_TIME=$BASE_TIME + echo "Error: Invalid JSON Response!" + echo " Defaulting sleep time to $SLEEP_TIME seconds." + return + fi + + REMAINING_CALLS=$(echo "$RATE_LIMIT_DATA" | jq -r '.resources.core.remaining // 0') + RESET_TIME=$(echo "$RATE_LIMIT_DATA" | jq -r '.resources.core.reset // 0') + + CURRENT_TIME=$(date +%s) + WAIT_PERIOD=$(( RESET_TIME - CURRENT_TIME )) + if (( WAIT_PERIOD < 0 )); then + SLEEP_TIME=$(( BASE_TIME * 2 )) + echo "Error: Invalid Wait Time Esitmate!" + echo " Defaulting sleep time to $SLEEP_TIME seconds." + return + fi + + if (( REMAINING_CALLS > 99 )); then + SLEEP_TIME=0 + elif (( REMAINING_CALLS > 1 )); then + SLEEP_TIME=$(( WAIT_PERIOD / REMAINING_CALLS )) + else + SLEEP_TIME=$(( WAIT_PERIOD + 60 )) + fi + + if (( SLEEP_TIME < 0 )); then + SLEEP_TIME=0 + fi + + echo "Calculated sleep time is $SLEEP_TIME seconds." + } + + handle_secondary_rate_limit() { + while (( RETRY_COUNT < MAX_RETRIES )); do + RESPONSE=$(curl -s -I --max-time 10 \ + -H "Authorization: Bearer $TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/rate_limit) + printf "Secondary Rate Limit Response:\n%s\n" "$RESPONSE" + + RETRY_BASE=$(echo "$RESPONSE" | grep -i '^retry-after:' | awk '{print $2}' | tr -d '\r') + if [[ ! -n "$RETRY_BASE" ]]; then + RETRY_AFTER=$(( $BASE_TIME / 16 )) + echo "'Retry-After' header not detected." + echo "Proceed after a token $RETRY_AFTER seconds." + sleep "$RETRY_AFTER" + break + fi + if (( RETRY_BASE < BASE_TIME )); then + RETRY_BASE=$BASE_TIME + fi + + SCALE_FACTOR=$(( RETRY_COUNT + 1 )) + RETRY_AFTER=$(( RETRY_BASE * SCALE_FACTOR * SCALE_FACTOR )) + echo "Secondary Rate Limit is Active." + echo "Wait $RETRY_AFTER seconds for reset..." + sleep "$RETRY_AFTER" + + RETRY_COUNT=$SCALE_FACTOR + if (( RETRY_COUNT >= MAX_RETRIES )); then + break + fi + done + } + + # Check for secondary rate limits + handle_secondary_rate_limit + + # Calculate sleep time for primary rate limits + calculate_sleep_time + + # Pause if necessary + if (( SLEEP_TIME == 0 )); then + echo "Skip Pause ... Far from Rate Limit." + else + if (( SLEEP_TIME < BASE_TIME )); then + echo "Defaulting sleep time to $BASE_TIME seconds." + SLEEP_TIME=$BASE_TIME + fi + echo "Apply ${SLEEP_TIME} Second Pause for Rate Limit." + sleep "$SLEEP_TIME" + fi diff --git a/.github/workflows/issues-close.yml b/.github/workflows/issues-close.yml index cb4ba342..0486e503 100644 --- a/.github/workflows/issues-close.yml +++ b/.github/workflows/issues-close.yml @@ -20,22 +20,16 @@ jobs: name: Flag or Close Issues runs-on: ubuntu-24.04 - if: github.event_name == 'schedule' || github.event.inputs.job_id == 'all' || github.event.inputs.job_id == 'stale' + if: github.actor == 'dakanji' && (github.event_name == 'schedule' || github.event.inputs.job_id == 'all' || github.event.inputs.job_id == 'stale') steps: - name: Repository Checkout uses: actions/checkout@v4 - - name: Check Rate Limit - id: rate-limit-check01 - uses: ./.github/actions/check-rate-limit + - name: Handle Rate Limits + uses: ./.github/actions/handle-rate-limits with: token: ${{ secrets.PAT_TOKEN }} - - name: Avoid Rate Limit - uses: ./.github/actions/avoid-rate-limit - with: - sleep_time: ${{ steps.rate-limit-check01.outputs.sleep_time }} - - name: Handle Cancelled/Duplicate/Invalid/Wierd/Not-Planned Issues uses: actions/stale@v9 with: @@ -50,17 +44,11 @@ jobs: remove-issue-stale-when-updated: false repo-token: ${{ secrets.PAT_TOKEN }} - - name: Check Rate Limit - id: rate-limit-check02 - uses: ./.github/actions/check-rate-limit + - name: Handle Rate Limits + uses: ./.github/actions/handle-rate-limits with: token: ${{ secrets.PAT_TOKEN }} - - name: Avoid Rate Limit - uses: ./.github/actions/avoid-rate-limit - with: - sleep_time: ${{ steps.rate-limit-check02.outputs.sleep_time }} - - name: Handle Incomplete Issues uses: actions/stale@v9 with: @@ -82,17 +70,11 @@ jobs: remove-issue-stale-when-updated: true repo-token: ${{ secrets.PAT_TOKEN }} - - name: Check Rate Limit - id: rate-limit-check03 - uses: ./.github/actions/check-rate-limit + - name: Handle Rate Limits + uses: ./.github/actions/handle-rate-limits with: token: ${{ secrets.PAT_TOKEN }} - - name: Avoid Rate Limit - uses: ./.github/actions/avoid-rate-limit - with: - sleep_time: ${{ steps.rate-limit-check03.outputs.sleep_time }} - - name: Handle No-Response Issues uses: actions/stale@v9 with: @@ -114,17 +96,11 @@ jobs: remove-issue-stale-when-updated: true repo-token: ${{ secrets.PAT_TOKEN }} - - name: Check Rate Limit - id: rate-limit-check04 - uses: ./.github/actions/check-rate-limit + - name: Handle Rate Limits + uses: ./.github/actions/handle-rate-limits with: token: ${{ secrets.PAT_TOKEN }} - - name: Avoid Rate Limit - uses: ./.github/actions/avoid-rate-limit - with: - sleep_time: ${{ steps.rate-limit-check04.outputs.sleep_time }} - - name: Catchall Closer uses: actions/stale@v9 with: diff --git a/.github/workflows/issues-lock.yml b/.github/workflows/issues-lock.yml index 90487171..4c091787 100644 --- a/.github/workflows/issues-lock.yml +++ b/.github/workflows/issues-lock.yml @@ -23,22 +23,9 @@ jobs: name: Lock Resolved Issues runs-on: ubuntu-24.04 - if: github.event_name == 'schedule' || github.event.inputs.job_id == 'all' || github.event.inputs.job_id == 'lock' + if: github.actor == 'dakanji' && (github.event_name == 'schedule' || github.event.inputs.job_id == 'all' || github.event.inputs.job_id == 'lock') steps: - - name: Repository Checkout - uses: actions/checkout@v4 - - - id: rate-limit-check01 - uses: ./.github/actions/check-rate-limit - with: - token: ${{ secrets.PAT_TOKEN }} - - - id: avoid-rate-limit-01 - uses: ./.github/actions/avoid-rate-limit - with: - sleep_time: ${{ steps.rate-limit-check01.outputs.sleep_time }} - - - id: main-action-01 + - name: Handle Thread Lock uses: dakanji/lock-threads@v5 with: github-token: ${{ secrets.PAT_TOKEN }} @@ -57,22 +44,17 @@ jobs: needs: [lock-threads-01] runs-on: ubuntu-24.04 - if: github.event_name == 'schedule' || github.event.inputs.job_id == 'all' || github.event.inputs.job_id == 'lock' + if: github.actor == 'dakanji' && (github.event_name == 'schedule' || github.event.inputs.job_id == 'all' || github.event.inputs.job_id == 'lock') steps: - name: Repository Checkout uses: actions/checkout@v4 - - id: rate-limit-check02 - uses: ./.github/actions/check-rate-limit + - name: Handle Rate Limits + uses: ./.github/actions/handle-rate-limits with: token: ${{ secrets.PAT_TOKEN }} - - id: avoid-rate-limit-02 - uses: ./.github/actions/avoid-rate-limit - with: - sleep_time: ${{ steps.rate-limit-check02.outputs.sleep_time }} - - - id: main-action-02 + - name: Handle Thread Lock uses: dakanji/lock-threads@v5 with: github-token: ${{ secrets.PAT_TOKEN }} @@ -91,22 +73,17 @@ jobs: needs: [lock-threads-02] runs-on: ubuntu-24.04 - if: github.event_name == 'schedule' || github.event.inputs.job_id == 'all' || github.event.inputs.job_id == 'lock' + if: github.actor == 'dakanji' && (github.event_name == 'schedule' || github.event.inputs.job_id == 'all' || github.event.inputs.job_id == 'lock') steps: - name: Repository Checkout uses: actions/checkout@v4 - - id: rate-limit-check03 - uses: ./.github/actions/check-rate-limit + - name: Handle Rate Limits + uses: ./.github/actions/handle-rate-limits with: token: ${{ secrets.PAT_TOKEN }} - - id: avoid-rate-limit-03 - uses: ./.github/actions/avoid-rate-limit - with: - sleep_time: ${{ steps.rate-limit-check03.outputs.sleep_time }} - - - id: main-action-03 + - name: Handle Thread Lock uses: dakanji/lock-threads@v5 with: github-token: ${{ secrets.PAT_TOKEN }} @@ -126,22 +103,17 @@ jobs: needs: [lock-threads-03] runs-on: ubuntu-24.04 - if: github.event_name == 'schedule' || github.event.inputs.job_id == 'all' || github.event.inputs.job_id == 'lock' + if: github.actor == 'dakanji' && (github.event_name == 'schedule' || github.event.inputs.job_id == 'all' || github.event.inputs.job_id == 'lock') steps: - name: Repository Checkout uses: actions/checkout@v4 - - id: rate-limit-check04 - uses: ./.github/actions/check-rate-limit + - name: Handle Rate Limits + uses: ./.github/actions/handle-rate-limits with: token: ${{ secrets.PAT_TOKEN }} - - id: avoid-rate-limit-04 - uses: ./.github/actions/avoid-rate-limit - with: - sleep_time: ${{ steps.rate-limit-check04.outputs.sleep_time }} - - - id: main-action-04 + - name: Handle Thread Lock uses: dakanji/lock-threads@v5 with: github-token: ${{ secrets.PAT_TOKEN }} @@ -160,22 +132,17 @@ jobs: needs: [lock-threads-04] runs-on: ubuntu-24.04 - if: github.event_name == 'schedule' || github.event.inputs.job_id == 'all' || github.event.inputs.job_id == 'lock' + if: github.actor == 'dakanji' && (github.event_name == 'schedule' || github.event.inputs.job_id == 'all' || github.event.inputs.job_id == 'lock') steps: - name: Repository Checkout uses: actions/checkout@v4 - - id: rate-limit-check05 - uses: ./.github/actions/check-rate-limit + - name: Handle Rate Limits + uses: ./.github/actions/handle-rate-limits with: token: ${{ secrets.PAT_TOKEN }} - - id: avoid-rate-limit-05 - uses: ./.github/actions/avoid-rate-limit - with: - sleep_time: ${{ steps.rate-limit-check05.outputs.sleep_time }} - - - id: main-action-05 + - name: Handle Thread Lock uses: dakanji/lock-threads@v5 with: github-token: ${{ secrets.PAT_TOKEN }} @@ -196,22 +163,17 @@ jobs: needs: [lock-threads-05] runs-on: ubuntu-24.04 - if: github.event_name == 'schedule' || github.event.inputs.job_id == 'all' || github.event.inputs.job_id == 'lock' + if: github.actor == 'dakanji' && (github.event_name == 'schedule' || github.event.inputs.job_id == 'all' || github.event.inputs.job_id == 'lock') steps: - name: Repository Checkout uses: actions/checkout@v4 - - id: rate-limit-check06 - uses: ./.github/actions/check-rate-limit + - name: Handle Rate Limits + uses: ./.github/actions/handle-rate-limits with: token: ${{ secrets.PAT_TOKEN }} - - id: avoid-rate-limit-06 - uses: ./.github/actions/avoid-rate-limit - with: - sleep_time: ${{ steps.rate-limit-check06.outputs.sleep_time }} - - - id: main-action-06 + - name: Handle Thread Lock uses: dakanji/lock-threads@v5 with: github-token: ${{ secrets.PAT_TOKEN }}