Как обработать ошибку при реализации функции экспоненциального отката? - PullRequest
0 голосов
/ 25 апреля 2018

Я использую концепцию метода backoff , чтобы повторить запрос, если произошла внутренняя ошибка сервера.Я имею в виду не 401, 403 или подобное.Моя цель - повторить запрос, если сервер не отвечает и / или отправка ответа занимает слишком много времени, например, в случае статуса pending.И я определил предельное время ожидания для этого (в службе).

Моя проблема заключается в том, что функция retryWhen вызывается во всех случаях / ошибках, включая 401.

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

Функция retryWhen возвращает наблюдаемый поток, который указывает, когда следует повторить попытку, и поэтому может 'в моем коде не работает должным образом.

public userLogin(userName, userPass: string) {
    this.theService.login(userName, userPass)
        .retryWhen(attempts => Observable.range(1, 3)
            .zip(attempts, i => i)
            .mergeMap(i => {
                console.log("delay retry by " + i + " second(s)");
                // Show a message to user to wait
                if ( i === 3 ) {
                    // Show Server doesn't respond... try later
                }
                return Observable.timer(i * 3000);
            })
        ).subscribe(
        res => {
            // handle and show response result
        },
        err => {
            console.log(err);
            if ( err === 401 ) {
                // handle 401 error
            } else {
                // handle other error
            }
        }
    );
}

Следующий вопрос также является своего рода решением той же проблемы, и я попытался использовать подсказку относительно mergeMap(error => {...}), ноэто не сработало для меня.

Любая идея, пожалуйста, как мне реструктурировать мой код, чтобы повторить запрос на случай внутренней ошибки сервера или чего-то вроде?как я уже говорил, нет 401, 403 или аналогичные.

1 Ответ

0 голосов
/ 25 апреля 2018

Вы можете перебросить занесенные в черный список ошибки в операторе retryWhen следующим образом:

/**
 * Performs a retry on an exponential backoff with an upper bounds.
 * Will rethrow the error if it is in the blacklist or the retry
 * attempts have exceeded the maximum.
 * @param {number} initialDelay
 * @param {number} maxRetry - maximum number of times to retry
 * @param {number[]} errorWhiteList - whitelist of errors to retry on (non-transient)
 */
function expontentialRetry(
  initialDelay,
  maxRetry,
  errorWhiteList
) {
  return (errors) => errors.scan((retryAttempts, error) => {
      if(!errorWhiteList.includes(error.status) || retryAttempts > maxRetry) {
        throw error;
      }
      return retryAttempts + 1;
    }, 0).switchMap((retryAttempts) => {
        // calculate exponential backoff
        let delay = Math.pow(2, retryAttempts - 1) * initialDelay;
        console.log(`Retry attempt #${retryAttempts} in ${delay}ms`);
        return Rx.Observable.timer(delay);
    });
}

let count = 0;
const fakeApiCall = Rx.Observable.create((o) => {
  if (count < 5) {
    o.error({ status: 504 });
  } else {
    o.error({ status: 500 });
  }
  count++;
});

fakeApiCall.retryWhen(expontentialRetry(100, 10, [504]))
.subscribe(
  (x) => { console.log('next', x); },
  (error) => { console.log('error', error); },
  () => { console.log('complete'); }
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.10/Rx.min.js"></script>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...