PromiseKitの使い方 その4

SwiftでPromiseを使える様になるPromiseKitの使い方 その4

PromiseKitでリトライ処理を実行する方法

非同期処理部分がネットワーク処理の様にある程度失敗することが前提で、リトライをさせたい場合の方法

まず、リトライの動きとしては、

という挙動をさせる

ソース

基本は公式のリトライ方法をベースに汎用的に使える様に以下の専用メソッドを作成

動作の流れとしては、

  1. リトライ回数を+1
  2. 非同期処理を実行
  3. 失敗すれば、recoverで一旦捕捉
  4. preRetryでリトライするかチェック
    (あるいは何か必要な処理。例えば、リトライ開始を通知するなど)
    • true: 次の処理へ
    • false: 失敗時のエラーをthrow
      (このメソッドの呼び出し元でエラー処理)
  5. リトライ上限回数内かチェック
    • 上限回数内: 1へ戻る
    • 上限回数を超えた: RetryErrorをthrow
      (※今回はリトライしたがエラーになったというのを知りたいので、専用のRetryErrorを作っているが、単に失敗時のエラーをthrowでも良い)

という感じになる

非同期処理に渡す引数がもし、複数ある場合は、タプルで渡してあげれば良い (次の使い方の例を参照)

使い方

例えば、「ログイン処理のAPIを3回までリトライ、ただし認証エラーの場合はリトライしない」といった挙動をさせたいなら、

firstly {
    retry(maxRepeat: 3, args: ("username", "1234"), task: login, preRetry: { error -> Bool in
        switch error as APIError {
        case .auth: return false
        default:    return true
        }
    })
}.then { result: String in
// 以下省略


func login(username: String, password: String) -> Promise<String> {
// 以下省略

といった感じで呼び出せばOK。 もちろん、loginメソッドの中でもPromiseを使える

リトライ部分を自分で一旦実装しないといけないのが面倒だが、Promiseを使わない場合と比べて、かなりシンプルに書けているのが良いと思う (本当はある程度フレームワーク側で実装されているとうれしいが、エラーをどうするとかの細かな部分はプロジェクトごとで違うので仕方がないのかも)

また、このリトライ自体の処理がメソッド内で完結しているのも良い。リトライ回数が内部に隠蔽されているので、誰かが勝手に回数を書き換えるみたいな妙なバグが入らない

さらに、シーケンスが複雑になってもコードが見にくくならない。 単なる通信のリトライぐらいならまだベタ書きでもなんとかなるかもしれないが、例えば、NFCの様にデータの書込や読込をさせるのに一連のコマンドのやりとりが必要で、さらにある処理をさせるにはその書込や読込を複数回行わないといけない。 また、当然電波を使っているので、コマンドのやりとり自体にもリトライ処理が必要といった場合、Promiseの威力は絶大になる

(ちなみに某案件ではベタ書きで実装されていたのをPromiseKitで書き直すと3分の1以下にソースが減ったという実績あり。 しかもベタ書きではリトライ処理が全くの未実装だったにも関わらず・・・)

開発環境

関連記事一覧