【问题标题】:How to create an RXjs RetryWhen with delay and limit on tries如何创建具有延迟和尝试限制的 RXjs RetryWhen
【发布时间】:2017-12-08 05:43:08
【问题描述】:

我正在尝试使用 retryWhen 进行 API 调用(使用 angular4),它在失败时重试。 我希望它延迟 500 毫秒,然后重试。这可以通过以下代码实现:

loadSomething(): Observable<SomeInterface> {
  return this.http.get(this.someEndpoint, commonHttpHeaders())
    .retryWhen(errors => errors.delay(500));
}

但这会一直尝试下去。我如何限制它,比如说 10 次?

谢谢!

【问题讨论】:

标签: angular rxjs observable


【解决方案1】:

您需要将限制应用于重试信号,例如,如果您只想重试 10 次:

loadSomething(): Observable<SomeInterface> {
  return this.http.get(this.someEndpoint, commonHttpHeaders())
    .retryWhen(errors => 
      // Time shift the retry
      errors.delay(500)
            // Only take 10 items
            .take(10)
            // Throw an exception to signal that the error needs to be propagated
            .concat(Rx.Observable.throw(new Error('Retry limit exceeded!'))
    );

编辑

一些评论者询问如何确保最后一个错误是被抛出的错误。答案有点不干净但同样强大,只需使用扁平化地图运算符之一(concatMap、mergeMap、switchMap)来检查您所在的索引。

注意:使用新的 RxJS 6 pipe 语法进行未来验证(这在 RxJS 5 的更高版本中也可用)。

loadSomething(): Observable<SomeInterface> {
  const retryPipeline = 
    // Still using retryWhen to handle errors
    retryWhen(errors => errors.pipe(
      // Use concat map to keep the errors in order and make sure they
      // aren't executed in parallel
      concatMap((e, i) => 
        // Executes a conditional Observable depending on the result
        // of the first argument
        iif(
          () => i > 10,
          // If the condition is true we throw the error (the last error)
          throwError(e),
          // Otherwise we pipe this back into our stream and delay the retry
          of(e).pipe(delay(500)) 
        )
      ) 
  ));

  return this.http.get(this.someEndpoint, commonHttpHeaders())
    // With the new syntax you can now share this pipeline between uses
    .pipe(retryPipeline)
}

【讨论】:

  • 如何让最终错误成为最后抛出的错误?
  • 注意:concat 上的错误会在原始 observable 错误抛出之前抛出。最后一次调用该方法。这可能会导致问题。
  • @Dominik 也许你已经明白了这一点,但我从你的 cmets 更新了我的答案。
  • 另外提醒一下,我们和同事做了一些测试,发现 throwError 总是被调用。因此,为了理解这一点,我们来到另一篇文章:stackoverflow.com/questions/54097971/…TLDR:“iif 的作用不是在另一条路径上执行一条路径,而是订阅一个 Observable 或另一个”
  • @JSantaCL 是正确的,但如果您真的想要暂停的副作用,您可以将子句包装在 defer
【解决方案2】:

使用

.retry(3)

重复源 observable 序列指定的次数或直到它成功终止。

https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/retry.md

【讨论】:

  • 这不会有任何延迟
猜你喜欢
  • 2021-01-13
  • 1970-01-01
  • 2017-01-01
  • 1970-01-01
  • 2019-05-20
  • 2017-12-12
  • 2018-08-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多