0

I get an error message saying "Rate limit exceeded" when I try to request historical data from GDAX. I use promises and setInterval to request historical price data from GDAX like this:

let promiseArray = //Array with promises
let j = 0;
let grabPrices = setInterval(() => {
    if (j === promiseArray.length) {
        //Do something when all promises have been resolved
    } 
    else {
        promiseArray[j].then(
            data => {
                //Work with data
            }
        ).catch(error => console.log('An error occurred: ' + error));
        j++;
    }
}, 1000) //I have even tried to use 10 seconds (10000) as a second argument to setInterval, but it doesn't make any difference.

FROM the official API documentation

Rate Limits When a rate limit is exceeded, a status of 429 Too Many Requests will be returned.

REST API PUBLIC ENDPOINTS We throttle public endpoints by IP: 3 requests per second, up to 6 requests per second in bursts.

4

2 回答 2

1

当你有一个承诺时,请求已经发出,所以你的 promiseArray 是一个正在进行的请求的数组。

假设我有一个 url 数组并用于fetch获取内容。用于将mapurl 映射到一个 Promise 并将 Promise 数组赋予Promise.all

Promise.all(
  urls.map(fetch)
).then(
  resulst=>...
);

如果 urls 有 10 个项目,此程序将立即发出 10 个请求。

您可以将该fetch函数传递给一个节流函数,该函数将以每秒仅调用 3 次的方式调度 fetch。油门函数将返回一个承诺,但不会立即调用 fetch。

可以在这里找到throttlePeriod 函数。如果您只想从该模块复制粘贴代码而不是导入整个模块,那么您还需要稍后的函数,因为throttlePeriod 依赖于它。

const fetchMaxThreePerSecond = throttlePeriod(3,1100)/*give it an extra 100*/(fetch)
Promise.all(
  urls.map(fetchMaxThreePerSecond)
).then(
  resulst=>...
);

这可以解决节流问题,但是如果您知道如何Promise.all工作,您就会知道如果只有一个拒绝,所有承诺都会拒绝。因此,如果您有 100 个 url 和 99 个解析但一个拒绝,您.then永远不会被调用。您将丢失 99 个成功的请求。

您可以传递一个Promise.all不会拒绝的承诺,您可以通过捕获被拒绝的承诺并在捕获中返回一个特殊值,您可以在处理结果时将其过滤掉:

const fetchMaxThreePerSecond = throttlePeriod(3,1100)/*give it an extra 100*/(fetch);
const Fail = function(reason){this.reason = reason;};
const isFail = x=>(x&&x.constructor)===Fail;
const isNotFail = x=>!isFail(x);
Promise.all(
  urls.map(
    url=>
      fetchMaxThreePerSecond(url)
      .catch(e=>new Fail([url,e]))//save url and error in Fail object
  )
)
.then(//even if a request fails, it will not reject
  results=>{
    const successes = results.filter(isNotFail);
    const failed = results.filter(isFail);
    if(failed.length!==0){
      console.log("some requests failed:");
      failed.forEach(
        (fail)=>{
          const [url,error] = fail.reason;
          console.log(`Url: ${url}`);
          console.log(JSON.stringify(error,undefined,2));
        }
      )
    }
  }
); 
于 2018-02-04T04:10:11.740 回答
0

当我将速率限制器设置为每 2.1 秒 3 次 API 调用时,我对 GDAX 历史调用没有任何问题。

当我将速率限制器设置为每 1.8 秒 3 次 API 调用时,我偶尔会遇到一些问题。

我已经用自动化测试测试了这些值。

重要提示:我对 GDAX 的所有调用共享相同的速率限制器(!)

要保存,请将@HMR 答案中的代码与我测试的参数一起使用。

于 2018-02-17T17:37:48.770 回答