我试图在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次。
但是,总是有一个buuut,我想使这个更抽象,用于各种用例,为此,我必须检查错误的类型。
只对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,但没有成功。
提前感谢!
发布于 2016-12-07 09:57:49
在RxJS 5中,flatMap()只是mergeMap():的别名。
问题在于您对retryWhen()操作符使用回调的方式。它只被调用一次,然后每次错误信号到达时,它就被推送到从这个回调中返回的可观察的返回。
在您的第二个示例中,您将从attempts.flatMap返回可观察到的内容,然后使用.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' }发布于 2017-10-30 11:11:06
我遇到了同样的问题,并找到了一种使用范围运算符来生成重试计数而不是计数器变量的方法,下面是代码:
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运算符以执行错误检查逻辑。
https://stackoverflow.com/questions/41005674
复制相似问题