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

时间:2016-02-25 17:21:21

标签: javascript node.js

我正在尝试回写处理特定API请求的最终功能,但此API具有一些限制性配额,尤其是对于请求/秒。我想创建API抽象层,如果请求/ s太多,它能够延迟函数执行,所以它的工作原理如下:

  1. 新请求到达(简单来说 - 调用库方法)
  2. 根据给定的限制(requests / s)
  3. 检查此请求是否可以立即执行
  4. 如果无法执行,请将其执行延迟至下一个可用时刻
  5. 如果此时有新请求到达,请进一步延迟执行或将其置于某个执行队列
  6. 我在等待队列长度方面没有任何限制。请求是带有node.js回调的函数调用,作为响应数据的最后一个参数。

    我想到为每个请求添加延迟,这将等于请求之间的最小可能时隙(表示为最小毫秒/请求),但它可能有点低效(总是在发送响应之前延迟函数)。

    您知道任何可以为我提供此类功能的库或简单解决方案吗?

2 个答案:

答案 0 :(得分:0)

保存最后一个请求的时间戳。

每当有新的传入请求时,检查自那时起是否经过了最小间隔,如果没有,则将该函数放入队列然后安排作业(除非已经安排了一个):

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.clock import Clock

Builder.load_string("""
<MyWidget>:  
    MyTextInput:
    MyTextInput:
""")

class MyTextInput(TextInput):
    def copy(self, data=''):
        # wrap copied text with ---
        if data:
            data = "--- {} ---".format(data)
        else:
            data = "--- {} ---".format(self.selection_text)
        return super(MyTextInput, self).copy(data)

class MyWidget(BoxLayout):
    pass

class ClientApp(App):
    def build(self):
        return MyWidget()

if __name__ == '__main__':
    ClientApp().run()

cut()从队列前面(setTimeout( processItemFromQueue, (lastTime + minInterval - new Date()).getTime() ) )接受一个作业,然后重新安排自己,除非队列为空。

答案 1 :(得分:0)

这个问题(以及最好的问题)的明确答案来自API文档本身。我们使用它几个月,它完全解决了我的问题。

在这种情况下,不是编写一些复杂的队列代码,最好的方法是利用JS处理异步代码的可能性,或者自己编写简单的 backoff ,或者使用众多优秀的库中的一个来使用如此。

因此,如果您偶然发现任何API限制(例如,配额,5xx等),您应该使用退避再次递归运行查询,但延迟时间越来越多(可以在此处找到更多有关退避的信息:https://en.wikipedia.org/wiki/Exponential_backoff )。并且,如果最终,在给定次数之后您再次失败 - 优雅地返回关于API不可用的错误。

以下使用示例(取自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();

NodeJS有许多退避库,利用Promise风格,回调风格甚至事件风格的退避处理(上面的例子是上面提到的第二个)。如果您了解退避算法本身,它们真的很容易使用。由于退避参数可以存储在配置中,如果退避失败太频繁,可以调整它们以获得更好的结果。