Help us understand the problem. What is going on with this article?

RxJSのretryWhen Operatorで複数回の遅延リトライ

More than 1 year has passed since last update.

はじめに

次のようなユースケースを想定してタイトルの通り RxJSのretryWhen Operatorsで複数回の遅延リトライ を試してみたいと思います。

  • rateLimitがあるWebAPIの呼び出し
  • AWS SDKなどの呼び出し時にリトライ処理に遅延時間を設定したい場合
    • 今回この記事を書こうと思ったきっかけも AWS Cognito SDKのrateLimit制限を避けるためでした...

たまに失敗して、連続で呼ぶとrateLimitで弾かれるソースを作成

リトライ処理の例を示す前に、リトライ対象となるモックのソースを作成します。
rateLimitがあるWebAPIをイメージするとわかりやすいかと思います。
以下の例では、次のようなエラーが発生するようにしています。

  • たまに andom error が発生
  • 1sの間に5回以上の呼び出して、ate limit error が発生
const rateLimitPerSec = 5;
let rateHistory: number[] = [];

// mock source
const source$ = () =>
  of(Math.floor(Math.random() * 5)).pipe(
    mergeMap((value) => {
      rateHistory = [Date.now(), ...rateHistory];
      rateHistory.length = rateLimitPerSec;

      const callTimeRateLimitAgo = +rateHistory[rateLimitPerSec - 1];

      if (!Number.isNaN(callTimeRateLimitAgo)) {
        const sec = 1 * 1000;
        if (Date.now() - callTimeRateLimitAgo <= sec) {
          return throwError('rate limit error occur');
        }
      }

      return of(value);
    }),
    mergeMap((value) => {
      if (value === 0) {
        return throwError('random error occur');
      }

      return of(value);
    }),
  );

※ ちょっと雑なところはありますが、雰囲気が伝わればいいかと

普通にretry Operatorでn回のリトライをする

上で作成したmockのソースに リトライ回数を指定して retry Operator を挟む

const retryCount = 5;

// retryを使用
source$()
  .pipe(
    retry(retryCount),
  )
  .subscribe((value) => console.log(value), (e) => console.log(e));

retryWhen Operatorでn回、1回失敗するごとにn * 1sずつ遅延リトライ

上で作成したmockのソースに retryWhen Operator を挟む
retryWhen でリトライ条件を指定することができるので、試行回数がretryCount以下だった場合は、
試行回数 * 遅延時間秒数待ってリトライするように条件指定をすることで実現できる。

const retryCount = 5;
const retryExecuteDuration = 1000;

// retryWhenを使用
source$()
  .pipe(
    retryWhen((errors) => {
      return errors.pipe(
        mergeMap((e, index) => {
          if (index > retryCount) {
            return throwError(e);
          }

          return timer((index + 1) * retryExecuteDuration);
        }),
      );
    }),
  )
  .subscribe((value) => console.log(value), (e) => console.log(e));

試したソース

https://stackblitz.com/edit/rxjs-retry-vs-retrywhen?file=index.ts

参考

daikiojm
Blog: http://daikiojm.hatenablog.com Scrapbox: https://scrapbox.io/daikiojm
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした