Promise.all при пакетном сетевом вызове не хватает памяти - PullRequest
0 голосов
/ 31 мая 2018

Я пытаюсь найти эффективный способ запуска серии пакетных сетевых запросов к API.API принимает массив идентификаторов и возвращает документ JSON для каждого из предоставленных идентификаторов, если он доступен в базе данных.Для небольшого количества идентификаторов, таких как 10 или 25, операция выполняется довольно быстро.Тем не менее, у меня есть 25 000+ (и растущих) идентификаторов, которые необходимо сделать при первом вызове.

Сначала я попытался разделить эти запросы на ~ 5000 идентификаторов в массиве, а затем с помощью Promise.all дождался возвращения всех запросов перед объединением данных.Это сократило время получения всех документов с 2 минут до 15 секунд (к счастью, это балансировка нагрузки).Все началось хорошо, но я знаю, что по мере роста приложения будет намного больше документов.Я попытался уменьшить размер, который я начал, до размера 1000, но это достигло предела стека и кучи.

Есть ли для меня более эффективный способ решить эту проблему только с помощью JavaScript?В конце концов, это приложение может легко увеличить необходимые документы с 25K до 50K за неделю, и слои кэширования, такие как Redis, в настоящее время недоступны.

Вот некоторый псевдокод того, как выглядит мой пакетный запрос:

const httpRequest = async arr => {
  return await axios.post(url, {
    keys: JSON.stringify(arr)
  });
}

// ids is an array of 25000+ strings
const batchRequest = async (ids) => {
  const batch = [];
  // Leave array ids from source immutable, clone it
  const cloneSource = Array.from(ids);

  let lengthOfIds = ids.length;

  while (cloneSource.length > 0) {
    // Break off the ids into separate arrays
    const sliced = cloneSource.slice(lengthOfIds - 1000, lengthOfIds);

    batch.push(sliced);
    // Reduce length, to make sure there are no duplicates
    lengthOfIds -= 1001;

    if (cloneSource.length === 1) {
      batch.push(cloneSource.splice(0, 1))
      break;
    }
  }

  const mapFetches = await Promise.all(httpRequest);
  return [
    mapFetches.reduce((acc, curr) => [...acc, ...curr.data], [])
  ];
}
...