我有一个Node应用程序,其中有一个Gremlin客户端:
var Gremlin = require('gremlin');
const client = Gremlin.createClient(
443,
config.endpoint,
{
"session": false,
"ssl": true,
"user": `/dbs/${config.database}/colls/${config.collection}`,
"password": config.primaryKey
}
);
然后我使用它来调用CosmoDB来添加一些记录:
async.forEach(pData, function (data, innercallback) {
if (data.type == 'Full'){
client.execute("g.addV('test').property('id', \"" + data.$.id + "\")", {}, innercallback);
} else {
innercallback(null);
}
}, outercallback);
然而,在我的Azure端,每秒有400个请求的限制,随后我收到错误:
ExceptionType : RequestRateTooLargeException
ExceptionMessage : Message: {"Errors":["Request rate is large"]}
有没有人对如何限制每秒发出的请求数量有任何想法,而无需在Azure上扩展(因为这需要更多:) :)
此外:
我尝试使用
async.forEachLimit(pData, 400, function (data, innercallback) {
if (data.type == 'Full'){
client.execute("g.addV('test').property('id', \"" + data.$.id + "\")", {}, innercallback);
} else {
innercallback(null);
}
}, outercallback);
然而,如果继续看RangeError: Maximum call stack size exceeded
如果它太高,否则如果我减少我就会得到相同的请求率太大的异常。
感谢。
答案 0 :(得分:1)
RangeError:超出最大调用堆栈大小
可能会发生这种情况,因为在innercallback
案例中同步调用了else
。它应该是:
} else {
process.nextTick(function() {
innercallback(null)
});
}
对forEachLimit
的调用看起来通常是正确的,但您需要确保在请求真正被触发(if
阻止)时,innercallback
不会在1秒之前调用保证一秒钟内不超过400个请求被解雇。最简单的方法是将回调执行完全延迟1秒钟:
client.execute("g.addV('test').property('id', \"" + data.$.id + "\")", {},
function(err) {
setTimeout(function() { innercallback(err); }, 1000);
});
更准确的解决方案是计算实际请求+响应时间,setTimeout
仅计算剩余时间为1秒。
作为进一步的改进,看起来你可以在做异步内容之前过滤你的pData
数组以摆脱if...else
,所以最终:
var pDataFull = pData.filter(function(data) => {
return data.type == 'Full';
});
async.forEachLimit(pDataFull, 400, function (data, innercallback) {
client.execute("g.addV('test').property('id', \"" + data.$.id +
"\")", {},
function(err) {
setTimeout(function() { innercallback(err); }, 1000);
}
);
}, outercallback);
答案 1 :(得分:0)
让我们先澄清一些事情。您没有400请求/秒的收集,但400 RU / s的收集。 RU代表请求单元,它们不会转换为请求。
大致是:
假设您的文档大小为1KB,则每秒只能添加80个文档。
现在我们已经完成了这项工作,听起来async.queue()可以帮助您。