From 6459141bb999822ebc39ae06083eb97d9bb742fe Mon Sep 17 00:00:00 2001 From: wa0x6e <495709+wa0x6e@users.noreply.github.com> Date: Mon, 13 Oct 2025 17:11:44 -0400 Subject: [PATCH] feat: handle 429 rate limit errors from overlord API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add custom RateLimitError class for rate limit detection - Switch from Promise.all to Promise.allSettled to process all requests - Save successful results even when rate limit is hit - Sleep for 1 minute when 429 error is detected before retrying - Failed proposals remain in pending state for next batch 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/helpers/proposalStrategiesValue.ts | 37 ++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/helpers/proposalStrategiesValue.ts b/src/helpers/proposalStrategiesValue.ts index 96bfc219..d19214eb 100644 --- a/src/helpers/proposalStrategiesValue.ts +++ b/src/helpers/proposalStrategiesValue.ts @@ -10,6 +10,13 @@ type Proposal = { strategies: any[]; }; +class RateLimitError extends Error { + constructor(message: string) { + super(message); + this.name = 'RateLimitError'; + } +} + const REFRESH_INTERVAL = 10 * 1000; const BATCH_SIZE = 25; @@ -32,27 +39,38 @@ async function getProposals(): Promise { async function refreshVpByStrategy(proposals: Proposal[]) { const query: string[] = []; const params: any[] = []; + let rateLimitHit = false; - const results = await Promise.all( + const results = await Promise.allSettled( proposals.map(async proposal => { try { const values = await getVpValueByStrategy(proposal); return { proposal, values, cb: CB.PENDING_COMPUTE }; - } catch (e) { + } catch (e: any) { console.log(e); + if (e.message && e.message.includes('HTTP error: 429')) { + rateLimitHit = true; + throw e; + } return { proposal, values: [], cb: CB.ERROR_SYNC }; } }) ); for (const result of results) { - query.push('UPDATE proposals SET vp_value_by_strategy = ?, cb = ? WHERE id = ? LIMIT 1'); - params.push(JSON.stringify(result.values), result.cb, result.proposal.id); + if (result.status === 'fulfilled') { + query.push('UPDATE proposals SET vp_value_by_strategy = ?, cb = ? WHERE id = ? LIMIT 1'); + params.push(JSON.stringify(result.value.values), result.value.cb, result.value.proposal.id); + } } if (query.length) { await db.queryAsync(query.join(';'), params); } + + if (rateLimitHit) { + throw new RateLimitError('Rate limit hit (429)'); + } } export default async function run() { @@ -60,7 +78,16 @@ export default async function run() { const proposals = await getProposals(); if (proposals.length) { - await refreshVpByStrategy(proposals); + try { + await refreshVpByStrategy(proposals); + } catch (e) { + if (e instanceof RateLimitError) { + console.log('Rate limit hit (429), sleeping for 1 minute...'); + await snapshot.utils.sleep(60 * 1000); + continue; + } + throw e; + } } if (proposals.length < BATCH_SIZE) {