Почему моя общая функция повтора Promise не ведет себя так, как моя? - PullRequest
0 голосов
/ 05 марта 2019

У меня есть неуниверсальный способ повторить вызов в Интернет с экспоненциальным отключением.Я пытаюсь реализовать его в общем виде, и способ, которым я до сих пор пользуюсь, наполовину работает.

Суть всего этого

Два способа реализации этого, как показано ниже, кажутся мне практически идентичными, и даже работают, когда request.get успешен каждый раз.

Однако когда request.get генерирует ошибку случайным образом, логика повторения работает по-другому.С первым неуниверсальным методом все работает как положено, вызовы повторяются до успеха или retries == 0. Со вторым более универсальным методом логика повторения повторяется снова и снова, пока retries == 0. Он не выполняет вызов в Интернет второй, третий, четвертый и т. Д. Раз.Что дает?

Я знаю все это, потому что у меня под контролем есть тесты, которые высмеивают метод request.get () и возвращаются с правильным ответом или с ошибкой.

МЕТОД РАБОТЫ

ОК, поэтому у меня есть рабочая логика рекурсивной повторной попытки, которая выглядит следующим образом:

function getPageOfThreadsWithRetry(access_token, nextPageToken, retries, delay) {
  return new Promise((resolve, reject) => {
    getPageOfThreads(access_token, nextPageToken).then((results) => {
        resolve(results);
    }).catch((err) => {
      if (retries == 0) {
        reject(err);
      } else {
        let retry = function() {
          retries--;
          delay = delay * DELAY_MULTIPLIER;
          resolve(getPageOfThreadsWithRetry(access_token, nextPageToken, retries, delay));
      }
      setTimeout(retry, delay);
    }
  });
});

getPageOfThreads (access_token, nextPageToken) - простая функция, которая возвращает обещание, которое оборачивает вызов request.get () и разрешается в случае успеха, и отклоняетв случае ошибки.

function getPageOfThreads(access_token, pageToken) {
  return new Promise((resolve, reject) => {
    let options = createOptions(access_token, pageToken);
    request.get(options, (error, response, body) => {
      if (!error && response.statusCode == 200) {
        body = JSON.parse(body);
        resolve(body)
      } else {
        reject(error);
      }
    });
  });
}

getPageOfThreadsWithRetry (...) вызывается изнутри работающей рекурсивной асинхронной функции, которая вызывает до тех пор, пока нет nextPageToken .Вызов выглядит так:

let delay = INIT_RETRY_DELAY;
let retries = MAX_RETRIES;
let response = await getPageOfThreadsWithRetry(access_token, nextPageToken, retries, delay).catch((error) => {

});

Это работает, как и ожидалось, getPageOfThreads () вызывается и возвращает response объект просто снова и снова, пока не будетnextPageToken.Если где-то там случайно выдается ошибка, он просто повторяет вызов с показательным отключением до тех пор, пока он либо не преуспеет, либо попытается сделать это больше, чем повторов раз.

HALFМЕТОД РАБОТЫ

Я хотел бы реализовать подобные вещи во многих местах моего приложения.Таким образом, я пытаюсь придумать универсальную функцию полезности, которая сделает это.До сих пор я придумал это (prms == обещание в этом случае):

function retryPromise(prms, retries, delay, delayMultiplier) {
  return new Promise((resolve, reject) => {
    prms.then((results) => {
      resolve(results);
    }).catch((err) => {
      if (retries == 0) {
        reject(err);
      } else {
        let retryFunc = function() {
          retries--;
          delay = delay * delayMultiplier;
          resolve(retryPromise(prms, retries, delay, delayMultiplier));
        }
        setTimeout(retryFunc, delay);
      }
    });
  });
}

Попытка назвать это так:

function getPageOfThreadsWithRetry(access_token, nextPageToken) {
  let delay = INIT_RETRY_DELAY;
  let retries = MAX_RETRIES;
  let delayMultiplier = DELAY_MULTIPLIER;
  let prms = getPageOfThreads(access_token, nextPageToken);
  return retryPromise(prms, retries, delay, delayMultiplier);
}

и вызов getPageOfThreadsWithRetry () сверху таким же образом, как и раньше

let response = await getPageOfThreadsWithRetry(access_token, nextPageToken).catch((err) => {
});

Этот второй способ предпочтительнее для меня, так как он может быть реализован везде, где у меня есть вызов в Интернет, и абстрагирует детали для всехкод, который зависит от ответа из Интернета.

Я знаю, что это довольно сложный вопрос, поэтому я действительно очень ценю любого, кто желает подумать и уделить ему время, и особенно тех, кто может иметьответ?

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

-Спасибо за потраченное время

1 Ответ

0 голосов
/ 05 марта 2019

В вашем первом методе request.get вызывается внутри рекурсивной функции getPageOfThreadsWithRetry.Но в вашем втором методе request.get вызывается вне рекурсивной функции retryPromise.

Я бы порекомендовал вам изменить подпись retryPromise на что-то вроде

function retryPromise(promiseCreator, retries, delay, delayMultiplier) {
  return new Promise((resolve, reject) => {
    promiseCreator()
      .then(resolve)
      .catch((err) => {
        if (retries == 0) {
          reject(err);
        } else {
          let retryFunc = function() {
            retries--;
            delay = delay * delayMultiplier;
            resolve(retryPromise(promiseCreator, retries, delay, delayMultiplier));
          }
          setTimeout(retryFunc, delay);
        }
      });
  });
}

и использовать еекак

function getPageOfThreadsWithRetry(access_token, nextPageToken) {
  let promiseCreator = () => getPageOfThreads(access_token, nextPageToken);
  return retryPromise(promiseCreator, retries, delay, delayMultiplier);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...