我正在尝试将retry
与delay
函数一起使用,我希望函数会在1000ms延迟后调用,但它不会,这里有什么错误?
看看控制台输出,它同时是16:22:48。
我希望有16:22:48,16:22:59 ......
canCreate: boolean;
getSomeFunction(): Observable<boolean> {
return new Observable<boolean>(
observer => {
const canCreate = null; // this is just null for now, will some value later
if (canCreate == null) {
observer.error('error');
} else {
observer.next(true);
}
observer.complete();
}
)
}
this.getSomeFunction()
.do((value) => {
this.cCreate = value;
}, (error) => {
console.log(error + new Date().toTimeString());
})
.delay(1000)
.retry(10)
.subscribe(
value => this.cCreate = value,
error => {
this.cCreate = false;
},
() => {}
);
}
和控制台结果是:
答案 0 :(得分:42)
delay()
用于在observable发出的事件之间引入延迟。但是观察者永远不会发出任何事件。它只会立即出错。
您正在寻找的是retryWhen()
,它允许在重试多长时间后决定:
RxJS 5:
.retryWhen(errors => errors.delay(1000).take(10))
RxJS 6:
import { retryWhen, delay, take } from 'rxjs/operators'
someFunction().pipe(
// ...
retryWhen(errors => errors.pipe(delay(1000), take(10)))
)
这将在10次尝试后完成整个观察。如果你想在10次尝试后出错整个observable,那么retryWhen回调返回的observable必须抛出:
RxJS 5:
.retryWhen(errors => errors.delay(1000).take(10).concat(Observable.throw()))
RxJS 6:
import { retryWhen, delay, take, concatMap, throwError } from 'rxjs/operators'
someFunction().pipe(
// ...
retryWhen(errors => errors.pipe(delay(1000), take(10), concatMap(throwError)))
)
答案 1 :(得分:21)
添加@JB Nizet的回答。如果您使用lettable运算符在rxjs 5+中编写此代码,请将其构造为
@Keep
private void CallbackHandler(String string_data, int int_data) {
// Some Code
}
答案 2 :(得分:2)
所有这些都是RxJS 6 +
您可以使用此软件包中经过全面测试的运算符,或向下滚动以查看源代码:)
npm i rxjs-boost
import { retryWithDelay } from 'rxjs-boost/operators';
obs$.pipe(
// will retry 4 times with a 1s delay before each try:
retryWithDelay(1000, 4)
);
由于其他大多数答案(或可能没有答案)都不符合我的所有标准,因此我将在下面列出解决方案。目标:
x
次。 ✅y
。 ✅strict: true
正确键入-但这很难弄乱。 ✅与其他所有答案一样,我们将使用retryWhen运算符来捕获错误。要跟踪重复次数,可以使用scan运算符。为了限制重复次数,我们只需要在map运算符内抛出一个错误即可。
原始来源使用throwIf,但是在那种情况下,我们可以简单地使用retryWithDelay中的rxjs-boost。
最后,我们将使用delay运算符来添加不同执行之间的延迟:
import { MonoTypeOperatorFunction } from 'rxjs';
import { delay as delayOperator, map, retryWhen, scan } from 'rxjs/operators';
export function retryWithDelay<T>(
delay: number,
count = 1
): MonoTypeOperatorFunction<T> {
return (input) =>
input.pipe(
retryWhen((errors) =>
errors.pipe(
scan((acc, error) => ({ count: acc.count + 1, error }), {
count: 0,
error: undefined as any,
}),
map((current) => {
if (current.count > count) {
throw current.error;
}
return current;
}),
delayOperator(delay)
)
)
);
}
答案 3 :(得分:1)
这可能对您有所帮助
let values$ = Rx.Observable.interval(1000).take(5);
let errorFixed = false;
values$
.map((val) => {
if(errorFixed) { return val; }
else if( val > 0 && val % 2 === 0) {
errorFixed = true;
throw { error : 'error' };
} else {
return val;
}
})
.retryWhen((err) => {
console.log('retrying again');
return err.delay(1000).take(3); // 3 times
})
.subscribe((val) => { console.log('value',val) });
答案 4 :(得分:1)
在rxjs版本6.3.3上工作
https://stackblitz.com/edit/http-basics-8swzpy
打开控制台并查看重试
示例代码
import { map, catchError, retryWhen, take, delay, concat } from 'rxjs/operators';
import { throwError } from 'rxjs';
export class ApiEXT {
static get apiURL(): string { return 'http://localhost:57886/api'; };
static httpCLIENT: HttpClient;
static POST(postOBJ: any, retryCOUNT: number = 0, retryITNERVAL: number = 1000) {
return this.httpCLIENT
.post(this.apiURL, JSON.stringify(postOBJ))
.pipe(
map(this.handleSUCCESS),
retryWhen(errors => errors.pipe(delay(retryITNERVAL), take(retryCOUNT), concat(throwError("Giving up Retry.!")))),
catchError(this.handleERROR));
}
private static handleSUCCESS(json_response: string): any {
//TODO: cast_and_return
return JSON.parse(json_response);
}
private static handleERROR(error: Response) {
let errorMSG: string;
switch (error.status) {
case -1: errorMSG = "(" + error.status + "/" + error.statusText + ")" + " Server Not Reachable.!"; break;
default: errorMSG = "(" + error.status + "/" + error.statusText + ")" + " Unknown Error while connecting with server.!"; break;
}
console.error(errorMSG);
return throwError(errorMSG);
}
}
答案 5 :(得分:1)
我得出这个结论,是为了重试http管道中的其他操作
import {delay as _delay, map, retryWhen} from 'rxjs/operators';
export const delayedRetry = (delay, retries = 1) => retryWhen(result => {
let _retries = 0;
return result.pipe(
_delay(delay),
map(error => {
if (_retries++ === retries) {
throw error;
}
return error;
}),
);
},
);
用法
http.pipe(
delayedRetry(1500, 2),
catchError((err) => {
this.toasterService.error($localize`:@@not-saved:Could not save`);
return of(false);
}),
finalize(() => this.sending = false),
).subscribe((success: boolean) => {
if (success === true) {
this.toasterService.success($localize`:@@saved:Saved`);
}
}
});
答案 6 :(得分:0)
我使用retryWhen
和Observable.Interval
提出了以下解决方案,但在此解决方案中,订阅的error
函数从不调用,
this.branchService.getCanCreate()
.do((value) => {
this.cCreate = value;
}, (error) => {
console.log('do', error + new Date().toTimeString());
})
.retryWhen(errors => {
return Observable.interval(1000).take(3).concat(Observable.throw('error')));
})
.subscribe(
value => {
this.cCreate = !!value
console.log('success', new Date().toTimeString());
},
error => {
console.log('subscribe', error + new Date().toTimeString());
this.cCreate = false;
},
() => {
console.log('finally', new Date().toTimeString());
}
);
答案 7 :(得分:0)
对于ngrx5 +,我们可以创建运算符:
function retryRequest(constructor: () => Observable, count: number, delayTime: number) {
let index = 0;
return of(1) // we need to repeat not the result of constructor(), but the call of constructor() itself
.pipe(
switchMap(constructor),
retryWhen(errors => errors.pipe(
delay(delayTime),
mergeMap(error => {
if (++index > count) {
return throwError(error);
}
return of(error);
})
))
);
}
答案 8 :(得分:0)
RxJS提供了重试运算符,该运算符在出现错误时为给定的计数重新订阅Observable。在引发错误之前,重试运算符将Observable重新分配给定的计数数量,如果仍然存在错误,则引发错误。重试有助于多次访问URL。由于网络带宽的原因,URL可能不会一次返回成功的数据,而在重新绑定时,URL可能会成功返回数据。如果重新输入后Observable中仍然存在错误,则catchError可用于返回带有用户定义的默认数据的Observable。
getBook(id:number):可观察{ 返回this.http.get(this.bookUrl +“ /” + id).pipe( 重试(3), catchError(err => { console.log(err); 返回(null); }) ); }
答案 9 :(得分:0)
我最近遇到了这个问题,发现可以改善公认的解决方案。
Observable.pipe(
retryWhen(errors => errors.pipe(
delay(1000),
take(10))),
first(v => true),
timeout(10000))
本质上,它所做的是重试,但是无需使用“ first”运算符添加任何(错误的)值即可立即完成。
如果在超时时间内找不到值,则会引发错误。