2016-12-06 8 views
2

私はretryWhenをHTTPコールで使用しようとしています。角2 Http RetryWhen

試みはこのように使用するとき、それは完璧に動作します:タイムアウトエラーを取得する場合

return this.http.get(`${environment.apiUrl}/track/${this.user.instance._id}/${this.currentPlayer.playlist.id}/next?s=${this.playerCounter}`, options) 
     .timeout(500, new TimeoutError(`Timeout trying to get next track. [instanceId=${this.user.instance._id}]`)) 
     .retryWhen(attempts => { 
     return Observable.range(1, 3).zip(attempts, i => i).flatMap(i => 3 === i ? Observable.throw(attempts) : Observable.timer(i * 1000)); 
     }) 

それは、3回の試行の最大になります。

しかし、常にbuuutを持っていますので、さまざまなユースケースで使用するためにこれをより抽象的にしたいと思います。このために、エラーのタイプを確認する必要があります。

テクニカルエロスだけが再試行されます。

私はこれをうまくやってみました。

.retryWhen(attempts => { 
    return attempts.flatMap(error => { 
     if(error instanceof TechnicalError) { 
     return Observable.range(1, 3).zip(attempts, i => i).flatMap(i => 3 === i ? Observable.throw(attempts) : Observable.timer(i * 1000)); 
     } else { 
     Observable.throw(error); 
     } 
    }); 
    }) 

それは最初の試行で停止し、Observable.timer()、どちらObservable.throw()を実行しません。

私はこの問題が最初のflatMapについてほとんど確信していますが、私は既にmergeMapを使用しようとしましたが、成功しませんでした。

ありがとうございます!

答えて

7

RxJS 5 flatMap()は、mergeMap() :)の別名です。

問題は、retryWhen()オペレータのコールバックを使用する方法にあります。一度だけ呼び出され、エラー信号が到着するたびに、このコールバックから返されたObservableにプッシュされます。

2番目の例では、Observableをattempts.flatMapから返してから、そのコールバックを.zip(attempts, i => i)で再度購読しています。しかし、このzip演算子は、値が既にattempts.flatMapによって消費された後に呼び出されるため、呼び出されません。また、これがObservable.range(1, 3)が常に最初から始まる理由です。

これは混乱しているようです。

  • retryWhen()のコールバックは1回だけ呼び出されます。
  • エラーが到着するたびにattempts.flatMap()のコールバックが呼び出されます。

だから、ちょうど次のように例えば、あなたのコードを再構築する必要があります。

var source = Observable.create(obs => { 
     obs.next(1); 
     obs.next(2); 
     obs.error(new TechnicalError('error from source')); 
    }) 
    .retryWhen(attempts => { 
     console.log('retryWhen callback'); 
     let count = 0; 

     return attempts.flatMap(error => { 
      if (error instanceof TechnicalError) { 
       console.log(error); 
       return ++count >= 3 ? Observable.throw(error) : Observable.timer(count * 1000); 
      } else { 
       return Observable.throw(error); 
      } 
     }); 
    }) 
    .subscribe(
     val => console.log(val), 
     err => console.log('subscribe error', err), 
     _ => console.log('complete') 
    ); 

これは、コンソールに出力します。

1 
2 
retryWhen callback 
TechnicalError { msg: 'error from source' } 
1 
2 
TechnicalError { msg: 'error from source' } 
1 
2 
TechnicalError { msg: 'error from source' } 
subscribe error TechnicalError { msg: 'error from source' } 

はライブデモを参照してください:https://jsbin.com/hobeda/3/edit?js,console

+0

"range"演算子を使用してカウンタ変数を取り除くことができれば、それはかなりうまくいくでしょう。 –

0

私は同じ問題に遭遇し、範囲演算子を使用してカウンタ変数の代わりに再試行回数を生成する方法を見つけました。ここではc ODEは:

var source = Observable.create(obs => { 
    obs.next(1); 
    obs.next(2); 
    obs.error(new TechnicalError('error from source')); 
}) 
    .retryWhen(error => { 
    console.log("Error occured, retryWhen initialized"); 
    return error.zip(Observable.range(1, 4), (error, i) => { 
     return { 
     ErrorObj: error, 
     RetryCount: i 
     } 
    }) 
     .map(obj => { 
     if (error instanceof TechnicalError) { 
      if (obj.RetryCount > 3) 
      throw obj.ErrorObj; 
      //Retry every one sec for 3 times 
      console.log('Retry # ' + obj.RetryCount); 
      return Observable.timer(obj.RetryCount * 1000); 
     } 
     else { 
      throw obj.ErrorObj; 
     } 
     }).concatAll() 
    }) 
    .subscribe(
    val => console.log(val), 
    err => console.log('subscribe error', err), 
    _ => console.log('complete') 
); 

アイデアは、それが一度だけ初期化されます範囲演算子を配置することです(retryWhenコールバック)ジップオペレータが新しい範囲の番号でエラーを組み合わせて、マップのオペレータにこれを渡します。この方法エラーチェックロジックを行うには