【问题标题】:Using Bottleneck to rate-limit API requests in a library使用瓶颈限制库中的 API 请求
【发布时间】:2021-01-12 03:13:14
【问题描述】:

我正在使用 TypeScript 编写 API 包装器。我希望代码是异步的,以便最大限度地满足相关 API 的速率限制。 API 希望以 1/秒的最大速率提交请求。

我打算实现一个实例化一次的 API 包装器,并允许使用对象到达不同的端点。例如,在更大的 API 中有一个 postpool 端点。我想像post_object.post.submit_request(argument1, ...)post_object.pool.submit_request(argument1, ...) 一样访问它们。

我创建了一个名为 state_info 的对象,该对象在各种对象之间传递,其中包含用户代理标头、登录信息(如果提供)以及来自瓶颈库的速率限制器对象。

我在测试时遇到的问题是我的程序似乎实际上并没有限制请求的速率;无论我将瓶颈参数中的限制更改为什么,每次请求都会在大约 0.600 秒内发生。

我认为这与传递速率限制器对象或从多个位置访问它有关,但我不确定。

首先,这里是 Model 对象的代码,它表示对 API 的访问。

import axios, { AxiosRequestConfig } from "axios";
import { StateInfo, Method } from "./interfaces";

export class Model {
  public stateInfo: StateInfo;

  constructor(stateInfo: StateInfo) {
    // Preserve rate limiter, user agent, etc.
    this.stateInfo = stateInfo;
  }

  //Updated to funcName = () => {} syntax to bind "this" to this class context.
  private submit_request = (query_url: string, method: Method) => {
    if (this.stateInfo.username && this.stateInfo.api_key) {
      const axiosConfig: AxiosRequestConfig = {
        method: method,
        url: query_url,
        headers: { "User-Agent": this.stateInfo.userAgent },
        auth: {
          username: this.stateInfo.username,
          password: this.stateInfo.api_key,
        },
      };
      return axios(axiosConfig);
    }  else {
      const axiosConfig: AxiosRequestConfig = {
        method: "get",
        url: query_url,
        headers: { "User-Agent": this.stateInfo.userAgent },
      };

      return axios(axiosConfig);
    }
  };

  public submit_throttled_request = (url: string, method: Method) => {
    return this.stateInfo.rateLimiter.schedule(
      this.submit_request,
      url,
      method
    );
  };
}

然后,我调用这个类的代码:

import { Model } from "./models/model";
import Bottleneck from "bottleneck";

const limiter: Bottleneck = new Bottleneck({ mintime: 1000, maxconcurrent: 1 });

const stateInfo = {
  rateLimiter: limiter,
  userAgent: "email@website.com | API Dev",
};

let modelObj: Model = new Model(stateInfo);

async function makeRequest() {
  try {
    let response = await modelObj.submit_throttled_request(
      "https://www.website.com/api",
      "get"
    );
    console.log(response.data.id + "|" + Date.now());
  } catch (err) {
    console.log(err);
  }
}

let start = new Date();
for (let i = 0; i < 20; i++) {
  makeRequest();
}

我的预期是,如果每秒只能提交一个请求,该操作至少需要 10 秒。然而,无论我为 mintime 添加什么内容,我的平均水平都是一半。

【问题讨论】:

    标签: javascript typescript api asynchronous rate-limiting


    【解决方案1】:

    经过一番摸索,我终于找到了自己问题的答案。

    事实证明,在bottleneck API reference"gotchas" 部分,他们注意到:

    如果您将对象的方法作为作业传递,您可能需要 bind() 对象:

    使用以下代码:

    // instead of this:
    limiter.schedule(object.doSomething);
    // do this:
    limiter.schedule(object.doSomething.bind(object));
    // or, wrap it in an arrow function instead:
    limiter.schedule(() => object.doSomething());
    

    这是我遇到的问题。我在没有绑定范围的情况下移交axios(axiosContext),所以没有任何东西被发送到瓶颈速率限制器。通过包装就像这样:this.state_info.rateLimiter.schedule(() =&gt; axios(axiosContext)); 我已经设法根据需要正确绑定上下文。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-08
      • 1970-01-01
      • 2019-02-25
      • 1970-01-01
      • 2018-08-29
      • 1970-01-01
      • 2012-01-12
      • 1970-01-01
      相关资源
      最近更新 更多