Node.js -使用每秒5个请求的API限制

qxsslcnc  于 2023-04-05  发布在  Node.js
关注(0)|答案(4)|浏览(246)

我有一个“脚本”,它可以向特定的API发送数千个请求。这个API每秒只允许5个请求(可能它的测量方法与我不同)。为了发出请求,我使用了request-promise框架,我用这个取代了普通的request-promise函数:

const request_promise  = require('request-promise')

function waitRetryPromise() {
  var count = 0 // keeps count of requests
  function rp(options) {
    const timedCall = (resolve) => setTimeout( ()=>resolve(rp(options)),1000) // recursive call
    count += 1
    if (count % 3 == 0) { // recalls after a second on every third request
      return new Promise(timedCall)
    } else {
      return request_promise(options)
    }
  }
  return rp
}

const rp = waitRetryPromise()

一旦有大约300个请求(给予或take)在短时间内被连续发出,这些请求就开始相互干扰了。有没有人有更好的解决方案?我认为递归调用这个函数会有所帮助,它确实解决了这个问题,但它没有解决这个问题。也许有一种模式可以将请求排队,一次只做几个?也许是一个库?
谢谢!

dgjrabp2

dgjrabp21#

好的,不要递归调用rp等,只要确保在请求之间有适当的延迟即可……每秒5次,即200ms

function waitRetryPromise() {
    let promise = Promise.resolve();
    return function rp(options) {
        return promise = promise
        .then(() => new Promise(resolve => setTimeout(resolve, 200)))
        .then(() => request_promise(options));
    }
}
const rp = waitRetryPromise();
7fyelxc5

7fyelxc52#

我的代码将运行TimedQueue,只要有工作要做。当所有工作完成时,process()方法将解析:

class Queue {
    constructor() {
        this.queue = [];
    }

    enqueue(obj) {
        return this.queue.push(obj);
    }

    dequeue() {
        return this.queue.shift();
    }

    hasWork() {
        return (this.queue.length > 0);
    }
}

function t_o(delay) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve();
        }, delay);
    });
}

class TimedQueue extends Queue {
    constructor(delay) {
        super();
        this.delay = delay;
    }

    dequeue() {
        return t_o(this.delay).then(() => {
            return super.dequeue();
        });
    }
    
    process(cb) {
        return this.dequeue().then(data => {
            cb(data);
            if (this.hasWork())
                return this.process(cb);
        });
    }
}

var q = new TimedQueue(500);

for (var request = 0; request < 10; ++request)
    q.enqueue(request);

q.process(console.log).then(function () {
    console.log('done');
});
js81xvg6

js81xvg63#

你可以使用mutex来同步运行在不同线程上的并发进程,并通过计时器来限制它们:

import { Mutex } from 'async-mutex';

const wait = (ms: number): Promise<void> => new Promise((res) => setTimeout(res, ms));

export class RateLimiter {
    private readonly mutex = new Mutex();

    private delay = 1000 / 2;

    public async run<T>(cb: () => Promise<T>): Promise<T> {
        const release = await this.mutex.acquire();

        try {
            return cb();
        } finally {
            // you can add `await` before to delay the result
            wait(this.delay).then(release);
        }
    }
}

示例用法:

// ...NestJS Controller
private readonly rateLimiter = new RateLimiter();

@Get('random')
public async random() {
    const result = await this.rateLimiter.run(async () => Math.random());

    return result;
}

📍 互斥体库documentation

xzlaal3s

xzlaal3s4#

我不确定,但也许你从下面得到一些想法

function placeAnOrder(orderNumber) {
    console.log("customer order:", orderNumber)
    cookAndDeliverFood(function () {
        console.log("food delivered order:", orderNumber);
    });
}

//  1 sec need to cook

function cookAndDeliverFood(callback){
    setTimeout(callback, 1000);
}

//users web request
placeAnOrder(1);
placeAnOrder(2);
placeAnOrder(3);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

相关问题