-
Notifications
You must be signed in to change notification settings - Fork 0
fix(scheduler): retry and gracefully defer shared installation rate limits #1245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c895eec
d67ead6
d007bce
9262430
7046ba9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -960,6 +960,8 @@ jobs: | |
| failures=0 | ||
| unavailable=0 | ||
| unavailable_repos=() | ||
| rate_limited=0 | ||
| rate_limited_repos=() | ||
| # These are organization-wide budgets. They must be consumed across | ||
| # the repository loop, not reset for every target repository; resetting | ||
| # them here can enqueue hundreds of long-running review jobs per sweep. | ||
|
|
@@ -1048,12 +1050,33 @@ jobs: | |
| # repository at all — the OpenCode app is not installed there or | ||
| # PR_REVIEW_MERGE_TOKEN does not cover it. The automation can never | ||
| # merge those PRs regardless, so this is a skipped, non-fatal | ||
| # "unavailable" repository, not a failure the sweep can act on. Any | ||
| # other non-zero exit is a genuine per-repository failure. | ||
| # "unavailable" repository, not a failure the sweep can act on. | ||
| # | ||
| # "API rate limit exceeded" means the shared GitHub App | ||
| # installation-token bucket (5,000-12,500 requests/hour, pooled | ||
| # across at least eight other central workflows that mint tokens | ||
| # for the same installation) is exhausted for this hourly window. | ||
| # That is routine cross-workflow contention, not a defect in this | ||
| # repository, and it self-heals on GitHub's own reset schedule; | ||
| # treating it as a hard failure previously turned one exhausted | ||
| # bucket into a permanently red */15 * * * * cron for as long as | ||
| # the contention lasted. Because the installation bucket is shared | ||
| # by every remaining repository, the current rotation stops after | ||
| # recording the first exhausted request instead of repeating the | ||
| # same bounded retries and queue-hygiene calls for every target. | ||
| # Deferred work is picked up on a later rotation after reset. | ||
| # | ||
| # Any other non-zero exit is a genuine per-repository failure. | ||
| if printf '%s' "$sweep_output" | grep -qF "Resource not accessible by integration"; then | ||
| echo "::warning::Skipping ${repo_full_name}: the sweep credential lacks access (HTTP 403 Resource not accessible by integration). Install the OpenCode app on this repository or grant PR_REVIEW_MERGE_TOKEN access to include it in the sweep." | ||
| unavailable=$((unavailable + 1)) | ||
| unavailable_repos+=("$repo_full_name") | ||
| elif printf '%s' "$sweep_output" | grep -qiF "API rate limit exceeded"; then | ||
| echo "::warning::Deferring ${repo_full_name} and stopping this rotation: the shared GitHub App installation-token rate limit is exhausted (HTTP 403 API rate limit exceeded). Deferred repositories are retried automatically on the next sweep rotation once the bucket resets." | ||
| rate_limited=$((rate_limited + 1)) | ||
| rate_limited_repos+=("$repo_full_name") | ||
| echo "::endgroup::" | ||
| break | ||
|
Comment on lines
+1074
to
+1079
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 Info: Queue-hygiene calls not covered by defer logic The defer-and-stop branch fires only when the Python scheduler exits non-zero. When it succeeds but the following queue-hygiene Was this helpful? React with 👍 or 👎 to provide feedback.
Comment on lines
+1074
to
+1079
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 Info: Rate-limit branch classifies via substring grep Classification uses Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| else | ||
| echo "::error::Queue sweep failed for ${repo_full_name}; see the decision log above for the concrete per-PR reason." | ||
| failures=$((failures + 1)) | ||
|
|
@@ -1213,6 +1236,13 @@ jobs: | |
| if [ "$unavailable" -gt 0 ]; then | ||
| echo "::warning::${unavailable} repository(ies) were skipped as unreachable by the sweep credential (HTTP 403): ${unavailable_repos[*]}. These do not fail the sweep; install the OpenCode app or grant PR_REVIEW_MERGE_TOKEN access to include them." | ||
| fi | ||
| if [ "$rate_limited" -gt 0 ]; then | ||
| # No fail-closed ceiling here, unlike ORG_SWEEP_MAX_UNAVAILABLE below: | ||
| # one exhausted shared installation-token bucket affects every | ||
| # remaining repository, so the rotation stops after the first | ||
| # observed exhaustion instead of multiplying retries and API calls. | ||
| echo "::warning::The organization sweep stopped after ${rate_limited} observed rate-limit exhaustion(s): ${rate_limited_repos[*]}. Deferred work does not fail this sweep and is retried automatically once the shared bucket resets." | ||
| fi | ||
| # Fail-closed guard: a handful of un-enrolled repositories is expected, | ||
| # but if MORE than ORG_SWEEP_MAX_UNAVAILABLE repositories become | ||
| # unreachable at once the sweep credential itself has regressed and the | ||
|
|
||
|
seonghobae marked this conversation as resolved.
|
Uh oh!
There was an error while loading. Please reload this page.