3

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);
  }
tec
  • 999
  • 3
  • 18
  • 40

3 Answers3

10

You can still use retry or retryWhen observable operators as long as your service function returns Observable.

Using retry:

this.infoService.getInfo()
  .pipe(
     retry(3), // you retry 3 times
     delay(1000) // each retry will start after 1 second,
  )
  .subscribe(res => {
     // success
  })

Using retryWhen:

this.infoService.getInfo()
  .pipe(
     retryWhen(errors => errors.pipe(
         // define conditions for retrying with some of observable operators
     )),
  )
  .subscribe(res => {
     // success
  })
critrange
  • 5,652
  • 2
  • 16
  • 47
2

Please try this way. Use rxjs retry() from rxjs/operators.

https://angular.io/guide/rx-library#retry-failed-observable

1

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
  }
tec
  • 999
  • 3
  • 18
  • 40