Angular9订阅失败如何重试?

How to retry a subscription when it fails in Angular 9?

上下文: 使用 Angular 9. 我正在等待后端可以接收请求。同时不是,有进度条loading。

问题:当后端还未可用时,订阅立即失败并进入方法.subscribe()的(错误)回调函数,带有类似 Http failure response for http://localhost:5555/api/info: 504 Gateway Timeout

的消息

我做了一些研究,我发现的示例修改了服务 class,其中 httpClient.get 存在,以重试 x 次请求,但我不能这样做ts 服务是自动生成的。

我的第一个想法是使用 while() 循环和一个标志,因此每次执行 (error) 时,标志都会为 false,然后重试订阅。但是会导致内存泄漏。

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

请试试这个方法。使用来自 rxjs/operators.

的 rxjs retry()

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

您仍然可以使用 retryretryWhen 可观察运算符,只要您的服务功能 returns Observable.

使用retry

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

使用retryWhen

this.infoService.getInfo()
  .pipe(
     retryWhen(errors => errors.pipe(
         // define conditions for retrying with some of observable operators
     )),
  )
  .subscribe(res => {
     // success
  })

这是最接近我想要的解决方案:

 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
  }