RxJs轮询实现中retryWhen重试超限后重复重试问题如何解决?
问题根因
你遇到的重试达到上限后仍重启新一轮重试的问题,核心原因是combineLatest中的timer(0, 1000)会持续按固定间隔发射值:当单次请求的5次重试全部失败后,retryWhen逻辑走完会让当前exhaustMap内的请求流正常结束,下一秒timer发射新值时就会触发全新的一轮请求+重试逻辑,进而出现无限循环重试的现象。
修复方案
调整逻辑如下:单次请求重试超限后不再直接结束当前请求流,而是抛出明确错误标识重试超限,外层根据需求选择终止整个轮询流,或是跳过当前轮次等待下一个定时周期再发起请求。
注意:需要从rxjs中导入
throwError、EMPTY、concatWith操作符。
以下是修复后的代码(以终止整个轮询流为例,X=1000ms,Y=5次重试):
polling$ = combineLatest([timer(0, 1000), this._filters]).pipe( exhaustMap((_) => this.noteDataService.getAll().pipe( retryWhen((error$) => error$.pipe( map((err, i) => ({ err, i })), tap(({ i }) => console.log(`Error receiving data, retry attempt ${i + 1}`) ), take(5), delay(1000), tap({ complete: () => console.log("Error receiving data, please try again later"), }), // 新增:重试次数用尽后抛出错误,代替原来的正常完成 concatWith(throwError(() => new Error('RETRY_LIMIT_EXCEEDED'))) ) ) ) ), // 新增:捕获重试超限错误,终止整个轮询流 catchError((err) => { if (err.message === 'RETRY_LIMIT_EXCEEDED') { return EMPTY; } return throwError(() => err); }) );
可选逻辑调整
如果你的业务需求是重试超限后不需要终止整个轮询,只是当前轮次失败,下一个定时周期仍要发起新的请求,只需把catchError逻辑移到exhaustMap内部的请求流pipe末尾即可,示例如下:
polling$ = combineLatest([timer(0, 1000), this._filters]).pipe( exhaustMap((_) => this.noteDataService.getAll().pipe( retryWhen((error$) => error$.pipe( map((err, i) => ({ err, i })), tap(({ i }) => console.log(`Error receiving data, retry attempt ${i + 1}`) ), take(5), delay(1000), tap({ complete: () => console.log("Error receiving data, please try again later"), }), concatWith(throwError(() => new Error('RETRY_LIMIT_EXCEEDED'))) ) ), catchError((err) => { // 捕获当前轮次的重试超限错误,不向外层抛出,等待下一个timer触发新轮次请求 return EMPTY; }) ) ) );
内容的提问来源于stack exchange,提问作者user7616817
相关产品推荐
相关产品推荐

