You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 19:31:23