Параллельные асинхронные запросы - отслеживайте необходимый тайм-аут - PullRequest
1 голос
/ 21 ноября 2019

При запросах Nominatim мне нужно сохранять время ожидания 1500 мс между каждым запросом. Как мне справиться с этим, если несколько параллельных запущенных процессов продолжают запускать эту функцию?

Код:

osmService:

export const getLocation = async (zipCode, street) => {
  if (!zipCode) {
    return {
      address: null,
      cacheHit: false,
    };
  }

  const cacheData = await getAddress(zipCode, street);

  if (cacheData && cacheData.length === 1) {
    return { address: cacheData[0].address, cacheHit: true };
  } if (cacheData && cacheData.length > 1) {
    logger.error('Found multiple address, this should not be', zipCode + street);
  }


  try {
    const responseObj = await getNominatimLocation(zipCode, street);
    if (responseObj) {
      const returnObj = {
        ...responseObj.address,
        lat: responseObj.lat,
        lon: responseObj.lon,
        displayName: responseObj.display_name,
      };
      await insertAddress(zipCode, street, null, returnObj);
      return {
        address: returnObj,
        cacheHit: false,
      };
    }
    return {
      address: null,
      cacheHit: false,
    };
  } catch (ex) {
    logger.error(`Error getting location from ${zipCode} ${street}`, ex);
  }
  return {
    address: null,
    cacheHit: false,
  };
};

Как видите, у меня есть слой кэшированиямежду. Поэтому, когда запрос был обработан кешем, мне не нужно ждать 1500 мс.

export const getNominatimLocation = async (zipCode, street, query, retries = 0) => {
  if (retries > 5) {
    return null;
  }
  try {
    const qs = {
      format: 'json',
      q: query,
      postalcode: zipCode,
      addressdetails: 1,
      country: 'Deutschland',
      street,
      'accept-language': 'de',
    };
    const response = await requestPromise()
      .get({
        url: OSM_SEARCH,
        qs,
        timeout: 12000,
        headers: {
          'User-Agent': 'xxxxxxx',
        },
      });
    return JSON.parse(response)[0];
  } catch (ex) {
    logger.info(`Nominatim timed out - retry ${retries}`, ex);
    await timeout(9000);
    return await getNominatimLocation(zipCode, street, query, retries + 1);
  }
};

Так как Nominatim часто истекает, мне нужно сделать этот рекурсивный вызов (не должен быть рекурсивным - просто проще).

Теперь давайте предположим, что у меня есть следующие задания (серверная часть), которые хотят получить местоположения

const jobA = asnyc () => {
  const {address, cacheHit} = await getLocation(10243);
  if(!cacheHit){
    await timeout(1500)
  }
}

const jobB = asnyc () => {
  const {address, cacheHit} = await getLocation(10245);
  if(!cacheHit){
    await timeout(1500)
  }
}

const startJobs = async () => {
 Promise.all([jobA(),jobB()])
 console.log('all jobs done');
}

Задания частично представляют мою текущую структуру кода. В моем коде задания выполняются больше (звоните в другие службы и т. Д.).

Теперь, когда у меня есть такая раскладка - как я могу сохранять 1500 мс между каждым вызовом Nominatim, когда нет cacheHit?

1 Ответ

1 голос
/ 21 ноября 2019

Вы можете использовать блокировку, которая разблокируется только каждые 1,5 секунды:

 let lock = Promise.resolve();
 let aquireLock = () => (lock = lock.then(() => new Promise(res => setTimeout(res, 1500))));

Тогда

await aquireLock();
// will only run every 1.5 seconds
...