Node.js - ограничение количества запросов, которые я делаю - PullRequest
0 голосов
/ 08 мая 2018

У меня есть приложение 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, если оно слишком велико, в противном случае, если я уменьшу, я получу ту же самую частоту запросов, слишком большое исключение.

Спасибо.

Ответы [ 2 ]

0 голосов
/ 08 мая 2018

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);
0 голосов
/ 08 мая 2018

Давайте сначала кое-что проясним. У вас нет коллекции 400 запросов / сек, но коллекции 400 RU / с. RU означают единицы запроса, и они не переводятся в запрос.

Грубо:

  • Запрос на извлечение документа размером 1 КБ обойдется в 1 RU.
  • Модификация для получения документа объемом 1 КБ обойдется в 5 RU.

Предполагая, что ваши документы имеют размер 1 КБ, вы можете добавлять только 80 документов в секунду.

Теперь, когда у нас это не так, похоже, что async.queue () может помочь вам.

...