简体   繁体   English

延迟执行函数(API调用)以在时间段内执行n次

[英]Delay function execution (API call) to execute n times in time period

I'm trying to write back end functionality that is handling requests to particular API, but this API has some restrictive quotas, especially for requests/sec. 我正在尝试写回用于处理对特定API的请求的后端功能,但是此API具有一些限制性配额,尤其是对于请求/秒。 I want to create API abstraction layer that is able of delaying function execution if there are too many requests/s, so it works like this: 我想创建一个API抽象层,如果请求太多,它可以延迟函数执行,因此它的工作方式如下:

  1. New request arrives (to put it simple - library method is invoked) 新请求到达(简单地说-调用库方法)
  2. Check if this request could be executed right now, according to given limit (requests/s) 根据给定的限制检查该请求是否可以立即执行(请求/秒)
  3. If it can't be executed, delay its execution till next available moment 如果无法执行,则将其执行延迟到下一个可用时刻
  4. If at this time a new request arrives, delay its execution further or put it on some execution queue 如果此时有新请求到达,则进一步延迟其执行或将其放入某个执行队列中

I don't have any constraints in terms of waiting queue length. 在等待队列长度方面,我没有任何限制。 Requests are function calls with node.js callbacks as the last param for responding with data. 请求是带有node.js回调的函数调用,作为对数据进行响应的最后一个参数。

I thought of adding delay to each request, which would be equal to the smallest possible slot between requests (expressed as minimal miliseconds/request), but it can be a bit inefficient (always delaying functions before sending response). 我想到了为每个请求添加延迟,这将等于请求之间的最小时间间隔(表示为最小毫秒/请求),但效率可能有点低下(总是在发送响应之前延迟功能)。

Do you know any library or simple solution that could provide me with such functionality? 您知道可以为我提供此类功能的任何库或简单解决方案吗?

Save the last request's timestamp. 保存上一个请求的时间戳。

Whenever you have a new incoming request, check if a minimum interval elapsed since then, if not, put the function in a queue then schedule a job (unless one was already scheduled): 每当有新的传入请求时,请检查此后是否经过了最小间隔;如果没有,请将该函数放在队列中,然后计划一个作业(除非已经安排了一个作业):

setTimeout(
  processItemFromQueue,
  (lastTime + minInterval - new Date()).getTime()
)

processItemFromQueue takes a job from the front of the queue ( shift ) then reschedules itself unless the queue is empty. processItemFromQueue从队列的最前面开始执行任务( shift ),然后重新计划自身,除非队列为空。

The definite answer for this problem (and the best one) came from the API documentation itself. 这个问题(也是最好的)的明确答案来自API文档本身。 We use it for a couple of months and it perfectly solved my problem. 我们使用了几个月,它完美地解决了我的问题。

In such cases, instead of writing some complicated queue code, the best way is to leverage JS possibility of handling asynchronous code and either write simple backoff by yourself or use one of many great libraries to use so. 在这种情况下,最好的方法是利用JS处理异步代码的可能性,而不是编写一些复杂的队列代码,或者自己编写简单的退避或使用许多优秀的库之一来使用。

So, if you stumble upon any API limits (eg quota, 5xx etc.), you should use backoff to recursively run the query again, but with increasing delay (more about backoff could be found here: https://en.wikipedia.org/wiki/Exponential_backoff ). 因此,如果偶然遇到任何API限制(例如配额,5xx等),则应使用退避来再次递归运行查询,但是会增加延迟(有关退避的更多信息,请参见: https://en.wikipedia。 org / wiki / Exponential_backoff )。 And, if finally, after given amount of times you fail again - gracefully return error about unavailability of the API. 而且,如果最终,在给定的时间之后,您将再次失败-优雅地返回有关API不可用的错误。

Example use below (taken from https://www.npmjs.com/package/backoff ): 下面的示例用法(摘自https://www.npmjs.com/package/backoff ):

var call = backoff.call(get, 'https://someaddress', function(err, res) {
    console.log('Num retries: ' + call.getNumRetries());

    if (err) {
        // Put your error handling code here.
        // Called ONLY IF backoff fails to help
        console.log('Error: ' + err.message); 
    } else {
        // Put your success code here
        console.log('Status: ' + res.statusCode);
    }
});

/*
 * When to retry. Here - 503 error code returned from the API
 */
call.retryIf(function(err) { return err.status == 503; }); 

/*
 * This lib offers two strategies - Exponential and Fibonacci. 
 * I'd suggest using the first one in most of the cases
 */
call.setStrategy(new backoff.ExponentialStrategy());

/*
 * Info how many times backoff should try to post request
 * before failing permanently
 */
call.failAfter(10);

// Triggers backoff to execute given function
call.start();

There are many backoff libraries for NodeJS, leveraging either Promise-style, callback-style or even event-style backoff handling (example above being second of the mentioned ones). NodeJS有许多退避库,它们利用Promise样式,回调样式甚至事件样式的退避处理(上述示例为第二个)。 They're really easy to use if you understand backoff algorithm itself. 如果您了解退避算法本身,它们真的很容易使用。 And as the backoff parameters could be stored in config, if backoff is failing too often, they could be adjusted to achieve better results. 并且由于退避参数可以存储在配置中,因此如果退避失败太多,则可以对其进行调整以获得更好的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM