【问题标题】:Retry a forkjoin call after one fails失败后重试 forkjoin 调用
【发布时间】:2021-09-06 15:42:01
【问题描述】:

我需要数组中每个服务的数据在 forkjoin 调用结束时返回,所以如果一个失败,我需要它再次尝试调用。

假设在下面的示例中,requests 数组中的三个项目之一失败。

request(): Observable<T> {
    const requests = [
      this.getService$.getOne(),
      this.getService$.getTwo(),
      this.getService$.getThree()
    ]

    return forkJoin(requests).pipe(
      map(res => this.formatFunc(res))
    );
  }

代码应该是什么样子,这样当调用this.request() 时,即使一个服务失败并且必须再次获取数据,我仍然可以从所有三个服务中获取数据?

我做了一些挖掘,发现人们正在添加this.getService$.getOne().catch(e =&gt; of([])) ...但这似乎只返回什么,而不是再次拨打电话。

我也看到过类似的使用retry

forkJoin(requests).pipe(
      retry(3),
      map(res => this.formatFunc(res))
    )

但是会重试所有三个调用还是只重做失败的一个?

【问题讨论】:

    标签: javascript angular rxjs


    【解决方案1】:

    虽然上面的答案有无效的错误处理,但这个想法是正确的:你必须分开处理每个请求的错误。应按如下方式进行:

    forkJoin([
    request1.pipe(retryWhen(genericRetryStrategy())),
    request2.pipe(retryWhen(genericRetryStrategy()))
    ])
    

    示例中提到的genericRetryStrategy 可以从此处获取(作为示例):https://www.learnrxjs.io/operators/error_handling/retrywhen.html 示例 2:可定制的增加持续时间的重试。

    您可以提供任何其他您想要的逻辑来代替它

    【讨论】:

      【解决方案2】:

      重试各个请求

      const { forkJoin, of, throwError } = rxjs;
      const { retry, tap } = rxjs.operators;
      
      let retryCount = 0;
      
      const requests = [
        of(1),
        of(2),
        throwError('thrown error').pipe(
          tap(
            val => { console.log(val); },
            error => {
              console.log(retryCount ? `Retry ${retryCount}:` : 'First:', error);
              retryCount++;
            }
          )
        )
      ];
      
      forkJoin(requests.map(request => request.pipe(retry(3)))).subscribe(
        val => { console.log(val); },
        error => { console.log('Sub:', error); }
      );
      &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js"&gt;&lt;/script&gt;

      【讨论】:

      • 确实如此。我刚刚制作了一个可运行的 sn-p 来证明它确实如此。
      • 由于forkJoin 失败,在订阅中您没有收到非错误值。
      【解决方案3】:

      mergemap处理forkjoin

      import { of,forkJoin,throwError, } from 'rxjs';
      import { retry,tap,mergeMap} from 'rxjs/operators';
      
      let r1=of([1,2,3]).pipe(tap(()=>console.log("r1 called ..."))),
          r2=of([4,5,6]).pipe(tap(()=>console.log("r2 called ..."))),
          r3=of([7,8,9]).pipe(tap(()=>console.log("r3 called ...")));
      
      of({})
      .pipe(
        mergeMap(
          ()=>forkJoin(r1,r2,r3,throwError("some error"))
        ),
        tap({
          next:()=>{
            console.log("next...")
          },
          error:()=>{
            console.log("error..");
          }
        }),
       retry(3)
      ).subscribe();
      

      这应该控制台error 4 次。

      这里是游乐场rxjs playground的链接

      【讨论】:

      • 这将使请求序列化而不是并行发生。
      猜你喜欢
      • 2015-07-23
      • 2021-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-11
      • 1970-01-01
      • 1970-01-01
      • 2015-09-09
      相关资源
      最近更新 更多