Skip to content

Commit ea84fef

Browse files
committed
fix: requeue repo on rate-limit exhaustion instead of failing
Signed-off-by: Joana Maia <jmaia@contractor.linuxfoundation.org>
1 parent 34a9c0d commit ea84fef

1 file changed

Lines changed: 20 additions & 2 deletions

File tree

services/apps/security_best_practices_worker/src/workflows/triggerSecurityInsightsCheckForRepos.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ export async function triggerSecurityInsightsCheckForRepos(
6464

6565
async function processRepo(repo: (typeof repos)[0]): Promise<void> {
6666
let attempts = 0
67+
// Distinguishes attempt exhaustion caused by transient rate-limits from exhaustion caused
68+
// by per-repo access failures. With MAX_TOKEN_ATTEMPTS == poolSize, a pool where every
69+
// token 403s in this run exits the loop via `attempts >= MAX_TOKEN_ATTEMPTS` rather than
70+
// via `!tokenInfo`, so requeue decisions have to be made here too — otherwise a rate-limit
71+
// wave would falsely fail the repo for the rest of the continueAsNew chain.
72+
let sawRateLimit = false
6773
while (attempts < MAX_TOKEN_ATTEMPTS) {
6874
const tokenInfo = getNextToken(tokenInfos, currentTimeMs)
6975
if (!tokenInfo) {
@@ -115,6 +121,7 @@ export async function triggerSecurityInsightsCheckForRepos(
115121
// batch startTime when details are missing so we still record something.
116122
tokenInfo.rateLimitedAt =
117123
extractFailureTimestamp(appFailure) ?? new Date(currentTimeMs).toISOString()
124+
sawRateLimit = true
118125
attempts++
119126
continue // retry with a different token
120127
} else if (appFailure?.type === 'TokenAuthError') {
@@ -145,8 +152,19 @@ export async function triggerSecurityInsightsCheckForRepos(
145152
}
146153

147154
if (attempts >= MAX_TOKEN_ATTEMPTS) {
148-
console.error(`Exhausted token attempts for repo ${repo.repoUrl}, skipping`)
149-
failedRepoUrls.push(repo.repoUrl)
155+
// If any attempt hit a rate-limit and not every token is permanently invalid, the
156+
// exhaustion is transient — requeue so the repo can be retried once cooldowns expire
157+
// (via the outer loop's `refreshExpiredRateLimits`) or on a later scheduled run.
158+
const allPermanentlyInvalid = tokenInfos.every((t) => t.isInvalid)
159+
if (sawRateLimit && !allPermanentlyInvalid) {
160+
console.warn(
161+
`Exhausted token attempts (rate-limit) for repo ${repo.repoUrl}, requeuing`,
162+
)
163+
queue.unshift(repo)
164+
} else {
165+
console.error(`Exhausted token attempts for repo ${repo.repoUrl}, skipping`)
166+
failedRepoUrls.push(repo.repoUrl)
167+
}
150168
}
151169
}
152170

0 commit comments

Comments
 (0)