【问题标题】:Angular 2 Http RetryWhenAngular 2 Http RetryWhen
【发布时间】:2016-12-06 21:57:12
【问题描述】:

我正在尝试在 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 次。

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

只会重试 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);
      }
    });
  })

它在第一次尝试时停止并且不执行Observable.timer(),也不执行Observable.throw()

我几乎可以肯定问题出在第一个flatMap上,我已经尝试使用mergeMap,但没有成功。

提前致谢!

【问题讨论】:

    标签: angular rxjs observable rxjs5 angular-http


    【解决方案1】:

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

    问题在于您对retryWhen() 运算符使用回调的方式。它只被调用一次,然后每次收到错误信号时,它都会被推送到此回调返回的 Observable。

    在您的第二个示例中,您从 attempts.flatMap 返回 Observable,然后使用 .zip(attempts, i => i) 再次订阅该回调。但是这个zip 运算符永远不会被调用,因为它是在attempts.flatMap 已经使用了值之后调用的。这也是为什么Observable.range(1, 3) 总是从头开始的原因。

    我知道这看起来很混乱。请注意:

    • retryWhen() 的回调只调用一次。
    • 每次出现错误时都会调用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

    【讨论】:

    • 您好,效果很好,如果我们可以使用“范围”运算符并去掉计数器变量会更优雅,但效果很好,谢谢!
    【解决方案2】:

    我遇到了同样的问题,并找到了一种使用范围运算符生成重试次数而不是计数器变量的方法,代码如下:

      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 回调),这样 zip 运算符会将任何错误与新的范围编号结合起来,并将其传递给 map 运算符以执行错误检查逻辑

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-01
      • 1970-01-01
      • 2023-03-16
      • 2016-04-03
      相关资源
      最近更新 更多