简体   繁体   中英

How to test rate limited HTTP request function?

I have an external service I am making HTTP requests to from Node.js. The service has current limitations that only 10 requests per second can be made. I have a naive rate limiter I wrote that I am trying to test, but falling down on timing of it. I know that Javascript times are not very accurate , but I'm getting wildly different swings, in the range of up to 50 milliseconds different.

Here's the gist of what I'm doing:

var RATE_LIMIT_MS = 100 // No more than 10 requests per second
var NEXT_WAIT_MS = 0

function goGetRequest(...) {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            function complete() {
                // Rollback next time after this request finishes
                NEXT_WAIT_MS = Math.max(0, NEXT_WAIT_MS - RATE_LIMIT_MS)
            }

            // ... requests are fired off here asynchronously...
            http.get(...).then(complete)

        }, NEXT_WAIT_MS)

        // Push time back on the queue
        NEXT_WAIT_MS += RATE_LIMIT_MS
    })
}

var chai = require('chai')
var expect = chai.expect

it('should rate limit requests properly', function() {
    var iterations = [0, 1, 2, 3, 4]
    var lastResponseMs = 0

    var promises = iterations.map(function(i) {
        return goGetRequest(...).
            then(function(result) {
                // Diff the times
                var thisResponseMs = Date.now()
                var thisDiffMs = Math.abs(thisResponseMs - lastResponseMs)

                expect(wrapper.results).to.not.be.empty
                expect(thisDiffMs, 'failed on pass ' + i).to.be.at.least(RATE_LIMIT_MS)

                // Move last response time forward
                lastResponseMs = thisResponseMs
            })
    })

    return Promise.all(promises)
})

What happens next is that the tests will fail at random passes. A time diff on 92 milliseconds on pass 2, a time diff of 68 milliseconds on pass 4.... what am I missing here? Thanks!

Javascript setTimeout and setInterval (as with any non-realtime code) is never precise. If you're using NodeJS however, you can try using Nanotimer:

https://www.npmjs.com/package/nanotimer

var NanoTimer = require('nanotimer');

var timerA = new NanoTimer();

timerA.setTimeout(yourFunction, '', NEXT_WAIT_MS);

Alternatively, I suggest simply testing that rate limit occurs and not to worry too much about exact precision. If you spam it with 11 requests consecutively (which should hopefully take less than one second), and it gets blocked, and one second later it is fine, then your test can be considered passing.

One final solution is to use exec() and call the OS sleep command, which is significantly more precise.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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