angularrxjsobservablesubscriptionangular9

How to retry a subscription when it fails?


Context: Working with Angular 9. I'm trying to wait the back-end to be available to receive requests. Meanwhile it's not, there is a progress bar loading.

Issue: when the back-end is not yet available, the subscription fails immediately and enters the (error) callback function of the method .subscribe(), with a message like Http failure response for http://localhost:5555/api/info: 504 Gateway Timeout

I did research a bit, and the examples I've found modify the service class where httpClient.get is present, to retry x times the request, but I can't do that as the ts service is auto generated.

My 1st idea was to use while() loop and a flag, so each time (error) was executed, the flag would be false and then retry the subscription. But it would lead to a memory leak.

checkIfBackendAvailable() {
    var backendAvailable = false;
    while(!backendAvailable){
      let subscription = this.infoService.getInfo().subscribe(
      (info) => {
        if (info) {
            backendAvailable = true;
            this.progressBarValue = 100
            // do somethings
         }
       }
        ,
        (error) => {
          clearTimeout(this.infoTimeOut);
          this.showMessage("back-end not available");
          this.stopLoadingBar();
          //do somethings
        }
      );
    }

    this.infoTimeOut = setTimeout(() => {
      if (!backendAvailable) {
        subscription.unsubscribe()
        this.showMessage("error");
        this.stopLoadingBar();
      }
    }, 120000);
  }

Solution

  • This is the most close solution to what I want:

     checkBackend() {
        console.log('Waiting for backend...');
        
        let infoObservable = this.infoService.getInfo().pipe(
          retryWhen(errors =>
            errors.pipe(
              delay(10000),
              tap(errorStatus => {
                //stop timeout if error
                this.stopInfoTimeOut();
                //parse the error, depending on the return from the http.get
                if (!errorStatus.includes('504')) {
                  throw errorStatus;
                }
                //run timeout when trying a new request
                this.runInfoTimeout();
              })
            )
          ))
          
        this.infoSubscription= infoObservable.subscribe({
          next: val => {
            if (val) {
              console.log('Backend available');
              this.stopInfoTimeOut();
            }
          },
          error: val => {
            console.log(val);
            this.stopInfoTimeOut();
            this.showMessage("Backend not available, try later");
          }, 
          complete: () => {}
        })
    
        this.runInfoTimeout();
    }
    
    stopInfoTimeOut(){
      clearTimeout(this.infoTimeOut);
    }
    
    runInfoTimeout(){
        //timeout for non error requests, waiting to be answered
        this.infoTimeOut =setTimeout(() => {
          console.log("Backend response time out");
          this.infoSubscription.unsubscribe()
          this.showMessage("Backend not available, try later");
        }, 120000);//2 min
      }