Angular 2 Http RetryWhen

Pau*_* GR 4 observable rxjs angular-http rxjs5 angular

我正在尝试retryWhen在HTTP调用中使用.

尝试使用时,它完美地工作:

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));
      })
Run Code Online (Sandbox Code Playgroud)

如果出现超时错误,最多会尝试3次.

但是,总是有一个buuut,我想让它更抽象地用于各种用例,为此,我必须检查错误的类型.

只会重试TechnicalErros.

所以我尝试了这个没有成功.

.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);
      }
    });
  })
Run Code Online (Sandbox Code Playgroud)

它首先尝试停止,不执行Observable.timer(),也不执行Observable.throw().

我几乎可以肯定问题是关于第一个flatMap,我已经尝试过使用mergeMap,没有成功.

提前致谢!

mar*_*tin 8

在RxJS中,5 flatMap()只是别名mergeMap():).

问题在于您对retryWhen()运算符使用回调的方式.它只被调用一次,然后每当一个错误信号到达时它被推送到从这个回调返回的Observable.

在你的第二个例子中,你将返回Observable attempts.flatMap,然后再次订阅它回调.zip(attempts, i => i).但是zip从不调用此运算符,因为它已在值已被消耗之后调用attempts.flatMap.这也是为什么Observable.range(1, 3)始终从头开始.

我知道这看起来令人困惑.请注意:

  • 回调for retryWhen()只调用一次.
  • attempts.flatMap()每次出现错误时都会调用callback .

因此,您只需重新构建代码,例如:

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')
    );
Run Code Online (Sandbox Code Playgroud)

这打印到控制台:

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' }
Run Code Online (Sandbox Code Playgroud)

观看现场演示:https://jsbin.com/hobeda/3/edit?js,console