【JavaScript】Promiseのリトライ処理をちゃちゃっと

こんにちは、ヘルスケア部門エンジニアの小林です。今回はJavaScript(Node.js含む)にてPromiseのリトライをどうやるかを考えてみます。

ちなみにPromiseでリトライを実現するためのパッケージはたくさんあります。ただ、リトライのためだけに余計なものも入ったパッケージを導入するのも嫌なので、担当プロダクトでは自分で実装したものを使っています。

catchをチェーンする

やりたいこと

  • 処理に成功したら終了
  • 処理に失敗したらやり直す
  • 規定回数以上失敗したら例外

これらを実現するだけなら、Promise.prototype.catch を必要回数分チェーンすれば実現できます。

コードで説明すると以下のようになります。

// 失敗したらリトライしたい処理
const func = () => { ... };

// 最大3回リトライ可能にする場合のPromise生成方法
const promise = Promise.reject().catch(func).catch(func).catch(func).catch(func);
  • 必ず1回は実行されてほしいので、最初にわざと reject する
    • こうすることで最初の catch に入る
  • 処理に成功する(例外が発生しない)と後続の catch はスルーされる
  • 処理に失敗する(例外が発生する)と直後の catch に入り、再度同じ処理をする
  • 後続に catch がない(規定回数リトライしてしまった)場合は例外が発生する
    • この後に更に catch をチェーンすれば例外処理が可能

このコードを汎用的なメソッドにしたのが以下になります。

function retryable(retryCount, func) {
  let promise = Promise.reject().catch(() => func());
  for (let i = 0; i < retryCount; i++) {
    promise = promise.catch(err => func());
  }
  return promise;
}

retryable(3, () => { ... })
  .catch(err => {
    // 例外処理
  });

いかがでしょうか。

追記

stackoverflowで同様のAnswerを投稿されている方がいらっしゃいました。

stackoverflow.com