J'essaie d'utiliser retry
avec la fonction delay
, je m'attends à ce que la fonction appelle après un délai de 1000 ms, mais elle ne peut pas, quelle peut être l'erreur ici?
Je m'attends à cela 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;
},
() => {}
);
}
et le résultat de la console est:
delay()
est utilisé pour introduire un délai entre les événements émis par l'observable. Mais l'observable n'émet aucun événement. Il se trompe immédiatement.
Ce que vous cherchez, c'est retryWhen()
, ce qui permet de décider après combien de temps réessayer:
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)))
)
Cela complétera le tout observable après 10 tentatives. Si vous souhaitez commettre une erreur sur l'ensemble de l'observable après 10 tentatives, l'observable renvoyé par retryLorsque le rappel doit renvoyer:
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)))
)
Fonctionne sur la version 6.3.3 de rxjs
https://stackblitz.com/edit/http-basics-8swzpy
Ouvrir la console et voir les tentatives
Exemple de code
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);
}
}
Cela peut vous aider
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) });
Je propose la solution suivante en utilisant retryWhen
et Observable.Interval
, mais dans cette solution, la fonction error
de subscribe n'appelle jamais,
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());
}
);
Pour ngrx5 +, nous pourrions créer un opérateur:
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);
})
))
);
}