web-dev-qa-db-fra.com

Comment créer un RXjs RetryWhen avec délai et limite d'essais

J'essaie de faire un appel API (en utilisant angular4), qui réessaie en cas d'échec, en utilisant retryWhen. Je veux qu'il retarde de 500 ms et réessaye. Cela peut être réalisé avec ce code:

loadSomething(): Observable<SomeInterface> {
  return this.http.get(this.someEndpoint, commonHttpHeaders())
    .retryWhen(errors => errors.delay(500));
}

Mais cela continuera d'essayer pour toujours. Comment puis-je le limiter, disons 10 fois?

Merci!

23
Tomer Almog

Vous devez appliquer la limite au signal de nouvelle tentative, par exemple si vous ne voulez que 10 tentatives:

loadSomething(): Observable<SomeInterface> {
  return this.http.get(this.someEndpoint, commonHttpHeaders())
    .retryWhen(errors => 
      // Time shift the retry
      errors.delay(500)
            // Only take 10 items
            .take(10)
            // Throw an exception to signal that the error needs to be propagated
            .concat(Rx.Observable.throw(new Error('Retry limit exceeded!'))
    );
}

MODIFIER

Certains commentateurs ont demandé comment s'assurer que la dernière erreur est bien celle qui est levée. La réponse est un peu moins nette mais non moins puissante, utilisez simplement l'un des opérateurs de carte d'aplatissement (concatMap, mergeMap, switchMap) pour vérifier à quel index vous vous trouvez.

Remarque: Utilisation de la nouvelle syntaxe RxJS 6 pipe pour l'épreuvage futur (elle est également disponible dans les versions ultérieures de RxJS 5).

loadSomething(): Observable<SomeInterface> {
  const retryPipeline = 
    // Still using retryWhen to handle errors
    retryWhen(errors => errors.pipe(
      // Use concat map to keep the errors in order and make sure they
      // aren't executed in parallel
      concatMap((e, i) => 
        // Executes a conditional Observable depending on the result
        // of the first argument
        iif(
          () => i > 10,
          // If the condition is true we throw the error (the last error)
          throwError(e),
          // Otherwise we pipe this back into our stream and delay the retry
          of(e).pipe(delay(500)) 
        )
      ) 

  return this.http.get(this.someEndpoint, commonHttpHeaders())
    // With the new syntax you can now share this pipeline between uses
    .pipe(retryPipeline)
}
51
paulpdaniels