我想用增加的时间间隔触发retrywhen(),
socketResponse.retryWhen(attempts => {
return attempts.zip(Observable.range(1, 4)).mergeMap(([error, i]) => {
console.log(`[socket] Wait ${i} seconds, then retry!`);
if (i === 4) {
console.log(`[socket] maxReconnectAttempts ${i} reached!`);
}
return Observable.timer(i * 1000);
});
});
上面的代码工作正常。 当前实施输出:
连接错误(第1次)
//连接成功。
连接错误(第二次)
现在我想重置套接字连接成功的等待时间。
期望的输出:
连接错误(第1次)
//连接成功。
连接错误(第二次)
[socket] 等待1秒,然后重试! //等待1秒
[socket] 等待2秒,然后重试! //等待2秒
但我不知道如何重置retrywhen()时间间隔。
答案 0 :(得分:1)
使用delayWhen
创建一个通知程序函数,该函数在每次错误发生后都会随着延迟的增加而发出。在下面的代码段中,我尝试增加0.5秒的倍数。但是,如果需要,可以使用其他时间序列。在这里,我还将展示如何限制重试次数并在这种情况下引发错误。
socketResponse$
.pipe(
retryWhen(errors =>
errors.pipe(
// delay(500), // fix delay: 0.5 sec
delayWhen((_,i) => timer(i*500)), // increasing delay: 0.5 sec multiple
tap(_ => console.log('retrying...')),
take(2), // max. retries: 2 x
concat(throwError('number of retries exceeded'))
)
)
)
.subscribe(
x => console.log('value:', x),
e => console.error('error:', e)
);
答案 1 :(得分:0)
我最近通过使用retryWhen处理程序的辅助类来解决这个问题。这是在RxJava而不是RxJS,但我认为这个概念是相同的。在我的情况下,如果我超过了我的最大重试次数,我想错误,所以你可能需要调整那部分来做你需要的。
private static class RetryWhenHandler implements Function<Observable<? extends Throwable>, Observable<?>> {
int retryCount = 0;
@Override
public Observable<?> apply(Observable<? extends Throwable> attempts) throws Exception {
if (++retryCount <= MAX_RETRIES) {
return Observable.timer(i, TimeUnit.Seconds);
} else {
return Observable.error(throwable);
}
}
}
然后,在上面的示例中:
RetryWhenHandler myHandler = new RetryWhenHandler();
socketResponse
.doOnNext(ignored -> myHandler.retryCount = 0)
.retryWhen(myHandler);
每次从observable获取更新时都应重置retryCount,以便下次遇到错误时为0。
答案 2 :(得分:0)
我也有同样的问题。我的目标是用可观察对象包装套接字连接。我希望可观察的网络永远不会完成(除非特别要求),并在出现任何错误时无限地重试连接。
这是我完成此任务的方法(使用rxjs 6+版)。我的retryWhen
运算符,在添加缩放等待持续时间scalingDuration
最高为maxDuration
的同时无限重试。
import { Observable, timer } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
export const infiniteRetryStrategy = (opts: { scalingDuration: number, maxDuration: number }, attempt?: () => number) => (attempts: Observable<{}>) => {
return attempts.pipe(
mergeMap((error, i) => {
// use attempt if we have it, otherwise use the number of errors received
const retryAttempt = attempt ? attempt() : i + 1;
const waitDuration = Math.min(opts.maxDuration, retryAttempt * opts.scalingDuration);
console.error(`Got error: ${error}. Retrying attempt ${retryAttempt} in ${waitDuration}ms`);
return timer(waitDuration);
})
);
};
用法非常简单。如果提供了attempt
功能,则可以从外部管理重试编号,因此可以在下一个刻度上将其重设。
import { retryWhen, tap } from 'rxjs/operators';
class Connection {
private reconnectionAttempt = 0;
public connect() {
// replace myConnectionObservable$ by your own observale
myConnectionObservable$.pipe(
retryWhen(
infiniteRetryStrategy({
scalingDuration: 1000,
maxDuration: 10000
}, () => ++this.reconnectionAttempt)
),
tap(() => this.reconnectionAttempt = 0)
).subscribe(
(cmd) => console.log(cmd),
(err) => console.error(err)
);
}
}
这不是完美的,因为您需要将状态保持在流之外,但这是我设法做到的唯一方法。欢迎使用任何更清洁的解决方案。