我有一个外部服务我正在从Node.js发出HTTP请求。该服务具有当前限制,每秒只能进行10次请求。我有一个天真的速率限制器,我写道,我试图测试,但落在它的时间。我知道Javascript times are not very accurate,但我的波动差异很大,不同的时间范围可达50毫秒。
以下是我正在做的事情的要点:
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)
})
接下来会发生的是,测试会随机传递失败。第2遍的时间差为92毫秒,第4遍的时差为68毫秒......我在这里缺少什么?谢谢!
答案 0 :(得分:0)
Javascript setTimeout和setInterval(与任何非实时代码一样)永远不会精确。但是,如果您正在使用NodeJS,则可以尝试使用Nanotimer:
https://www.npmjs.com/package/nanotimer
var NanoTimer = require('nanotimer');
var timerA = new NanoTimer();
timerA.setTimeout(yourFunction, '', NEXT_WAIT_MS);
或者,我建议只测试速率限制发生,而不要过分担心精确度。如果你连续11次请求垃圾邮件(希望不到一秒钟),它会被阻止,一秒钟就可以了,那么你的测试可以被视为通过。
最后一个解决方案是使用exec()
并调用操作系统sleep
命令,这更加精确。