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

开发Discord API交互库:限流队列如何返回REST请求结果?

解决Discord API限流队列请求结果返回问题

核心问题是当前入队列的请求仅返回队列长度,无法传递实际响应结果。要解决这个问题,需让每个入队请求关联一个Promise,待队列处理完成后通过resolve/reject传递结果或错误。

具体修改方案

1. 调整队列存储结构

不再仅存储请求配置,改为存储包含请求配置、Promise解析函数的对象:

// 修改ratelimit的queue类型,存储带resolve/reject的请求项
this.ratelimit = {
  queue: [] as Array<{
    options: InternalRequest;
    resolve: (value: AxiosResponse | unknown) => void;
    reject: (reason?: any) => void;
  }>,
  timer: null as NodeJS.Timeout | null,
  time: null as number | null,
};

2. 修改raw方法返回Promise

当请求需要入队时,创建Promise并将resolve/reject存入队列,返回该Promise给调用者:

public async raw(options: InternalRequest) {
  const globalRateLimit = Number(await this.REST.redisClient.incr("ratelimit:global"));
  if (globalRateLimit > 2) {
    await this.REST.redisClient.decr("ratelimit:global");
    // 返回Promise,将resolve/reject绑定到队列项
    return new Promise((resolve, reject) => {
      this.ratelimit.queue.push({ options, resolve, reject });
      this.manageQueue();
    });
  } else {
    try {
      const result = await this.request(options);
      // 请求完成后递减限流计数
      await this.REST.redisClient.decr("ratelimit:global");
      return result;
    } catch (err) {
      await this.REST.redisClient.decr("ratelimit:global");
      throw err;
    }
  }
}

3. 调整processQueue方法传递结果

处理队列请求时,执行完成后调用对应resolve/reject传递结果:

private async processQueue() {
  if (this.ratelimit.queue.length === 0) {
    this.manageQueue();
    return;
  }
  const globalRateLimit = Number(await this.REST.redisClient.incr("ratelimit:global"));
  if (globalRateLimit > 2) {
    await this.REST.redisClient.decr("ratelimit:global");
    this.manageQueue();
    return;
  }

  const queueItem = this.ratelimit.queue.shift();
  if (!queueItem) return;

  try {
    const result = await this.request(queueItem.options);
    queueItem.resolve(result);
    await this.REST.redisClient.decr("ratelimit:global");
  } catch (err) {
    queueItem.reject(err);
    await this.REST.redisClient.decr("ratelimit:global");
  }

  // 继续处理下一个请求
  if (this.ratelimit.queue.length > 0) {
    this.processQueue();
  } else {
    this.ratelimit.timer = null;
  }
}

4. 修复request方法的错误处理

当前catch仅打印错误,需抛出错误让上层Promise捕获:

private async request(options: InternalRequest) {
  console.log("REQUEST RUN!");
  const request = this.formatRequest(options);

  const res = await axios(request.url, {
    method: options.requestMethod,
    headers: request.headers,
  }).catch((err) => {
    console.log("ERROR!");
    throw err; // 抛出错误,让Promise捕获并传递给调用者
  });

  return this.parseResponse(res); // 返回解析后的数据
}

关键逻辑说明

  • 每个入队请求绑定独立的Promise解析函数,调用await this.client.rest.get(...)时,即使请求被入队,也会等待Promise resolve后拿到结果。
  • 请求执行完成后必须递减Redis中的限流计数,避免计数累加导致后续请求无法正常执行。
  • 队列处理前需再次检查限流状态,确保不会超出阈值再执行下一个请求。

内容的提问来源于stack exchange,提问作者Toby Chambers

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 16:31:33