如何在for...of循环中重试失败的Notion API调用?
解决Notion JS SDK分页API的错误重试问题
你当前的代码把整个分页迭代包在了单个try/catch块中,一旦出错就会终止整个循环,无法回到失败的分页节点重试。JS没有Ruby那样的retry关键字,所以需要手动控制分页状态,在出错时从失败的位置重新发起请求。
方案:手动实现分页+单请求重试
放弃直接用for await...of遍历iteratePaginatedAPI,改为自己处理分页游标(cursor),同时给每一次API请求加上重试逻辑,精准重试失败的分页:
async function* queryNotion(listFn, firstPageArgs, retryOptions = { maxRetries: 3, initialDelay: 1000 }) { const { maxRetries, initialDelay } = retryOptions; let cursor = firstPageArgs.start_cursor; let hasMore = true; while (hasMore) { let attempt = 0; let response; while (attempt < maxRetries) { try { const args = { ...firstPageArgs, start_cursor: cursor }; response = await listFn(args); break; // 请求成功,跳出重试循环 } catch (error) { if (error.code === APIErrorCode.RateLimited) { attempt++; const delay = initialDelay * Math.pow(2, attempt - 1); // 指数退避,避免持续触发限流 console.log(`触发限流,第${attempt}次重试,等待${delay}ms`); await new Promise(resolve => setTimeout(resolve, delay)); } else { // 非限流错误直接抛出,不做无效重试 throw error; } } } if (!response) { throw new Error(`超过最大重试次数(${maxRetries}),请求失败`); } // 输出当前页的所有结果 yield* response.results; // 更新分页状态,准备下一页请求 hasMore = response.has_more; cursor = response.next_cursor; } }
方案优势
- 手动维护
cursor和hasMore状态,确保重试时精准回到失败的分页节点 - 采用指数退避策略,比固定等待1秒更适配Notion API的限流机制
- 仅针对限流错误重试,其他错误直接抛出,避免无意义的重试循环
使用方式
和你原本的调用逻辑完全一致:
for await (const item of queryNotion(notion.databases.query, { database_id: "你的数据库ID" })) { console.log(item); // 处理单条数据 }
补充说明
如果坚持要基于iteratePaginatedAPI封装,会面临一个问题:该工具抛出错误时,无法直接获取当前的游标位置,导致无法精准重试。手动实现分页逻辑复杂度不高,反而能获得更灵活的错误控制能力。
内容的提问来源于stack exchange,提问作者linkyndy
相关产品推荐
相关产品推荐

