Rxjs Retry with Delay function

前端 未结 10 2360
忘了有多久
忘了有多久 2020-11-30 06:32

I am trying to use retry with delay function, I expect function will call after 1000ms delay, but it doesnot, what can be error here? look at conso

相关标签:
10条回答
  • 2020-11-30 06:51

    I came to this conclusion, in order to retry with other operations in the http pipe

    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;
          }),
        );
      },
    );
    

    Usage

        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`);
            }
          }
        });
    
    0 讨论(0)
  • 2020-11-30 06:53

    Works on rxjs version 6.3.3

    https://stackblitz.com/edit/http-basics-8swzpy

    Open Console and see the retries

    Sample 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, retryINTERVAL: number = 1000) {
            return this.httpCLIENT
                .post(this.apiURL, JSON.stringify(postOBJ))
                .pipe(
                    map(this.handleSUCCESS),
                    retryWhen(errors => errors.pipe(delay(retryINTERVAL), 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);
        }
    
    }
    
    0 讨论(0)
  • 2020-11-30 06:57

    All of this is RxJS 6+


    TL;DR

    You could use the fully tested operator from this package, or scroll down to see the source :)

    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)
    );
    

    Criteria

    As most (or maybe none) of the other answer didn't meet all of my criteria, I'll list my solution below. Goals:

    • Emits & completes regularly if no error is thrown. ✅
    • Retries x times if an error is thrown. ✅
    • Has a delay of y before each retry. ✅
    • Returns the last emitted error. (A lot of other answers were struggling with this.) ✅
    • Correct typing with strict: true – but this was quite difficult to mess up. ✅

    Solution

    As every other answer we'll use the retryWhen operator to catch the errors. To track the amount of repetitions can use the scan operator. To limit the amount of repetitions we'll simply throw an error inside a map operator.

    The original source uses throwIf, but in that case we could simply use retryWithDelay from rxjs-boost.

    Last we'll use the delay operator to add the delay between the different executions:

    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)
            )
          )
        );
    }
    

    Sources

    • rxjs-boost
    • Original Source
    • Spec File with Tests – probably comes in handy
    0 讨论(0)
  • 2020-11-30 07:00

    I recently had this problem, and found that the accepted solution could be improved.

    Observable.pipe(
         retryWhen(errors => errors.pipe(
          delay(1000),
          take(10))),
        first(v => true),
        timeout(10000))
    

    What it essentially does is to retry as mentioned, but this finishes right away without adding any (erroneous) value using the 'first' operator.

    If it cannot find a value within the timeout timeframe, an error is raised.

    0 讨论(0)
  • 2020-11-30 07:02

    This may help you

    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) });
    
    0 讨论(0)
  • 2020-11-30 07:05

    To add on to @JB Nizet's answer. If you're writing this in rxjs 5+ with lettable operators, structure it as

    retryWhen(errors => errors.pipe(delay(1000), take(5)))

    0 讨论(0)
提交回复
热议问题