3

I have a service that is responsible to execute a httpClient.get every x seconds, using a timer. I need this timer to start running whenever the service is up, so the timer is defined in the service constructor. According to my understanding, the subscription should be registered in the timer scope as seen below (I don't want to change it if there's no need, unless it is incorrect).

The all system is working fine as long as there are no errors\exceptions\error 500 exception from the backend server. Now, I need 2 things:

  1. I would like to catchError whenever there is a problem in the backend server.
  2. I would like the observer to keep running according to the timer times (to the next tick), even if there is an exception. My final result should be reaching the popUpAlert in the component whenever there is exception See my code - this the webapi controller:
public IActionResult getSomeErrorAsTest()
{
    try
    {
        throw new Exception("Serer error");
    }
    catch(Exception ex)
    {
        return StatusCode(StatusCodes.Status500InternalServerError, new List<string>());
        //throw ex;
    }
}

This is the service (assume that the data changes in every get request - no need to implement if it really do):

export class MyService
{
    MyDataSubject = new Subject<any[]>();
    MyDataChanged :Observable>any[]> = this.MyDataSubject.asObservable();
    
    subscribe :Subscription;
    constructor(private httpClient : HttpClient)
    {
        this.subscribe = timer(0, 30000).pipe(
        switchMap(()=>
            this.getData())).subscribe();
    }
    getData()
    {
        return this.httpClient.get<any[]>(<controller url>)
        .pipe(
            tap(res =>
            {
                this.MyDataSubject.next(res);
            }),
            catchError(error =>
                {
                    debugger;//I would expect to catch the debugger here, but nothing happens
                    return throwError(error);
                })
            )
    }
}   

The consumer component:

export class MyComponent (private mySrv : MyService)
{
    getMyData()
    {
        let sub =this.mySrv.MyDataChanged.subscribe(result => doSomething(),
                                                    error=> popUpAlert());
    }
}
Guy E
  • 1,775
  • 2
  • 27
  • 55
  • 1
    I would move the whole error handling into the service. Call `popUpAlert()` in `catchError` in your service and return `of(null)`. Let your component handle the case when the result is `null` but no error case. See my answer here: https://stackoverflow.com/a/54790621/9423231 – frido Aug 23 '20 at 11:14
  • 1) `MyDataSubject` is not aware that any error is thrown. Because its thrown in another stream 2) You can not catch the error thrown by `throwError` operator. It won't cause an error, it will emit a value instead. – Eldar Aug 23 '20 at 11:39
  • Unrelated to your problem (Rafi's answer hits the nail on the head), but Services in Angular support some of the same lifecycle callbacks as Components (including OnInit and OnDestroy). You would probably be better off starting the timer in an init hook and destroying the subscription in a destory hook. – John Dengis Aug 23 '20 at 23:13

1 Answers1

7

CatchError operator allows to handle error, but doesn't change nature of observable - error is terminal condition to given observable so emission will stop. CatchError allows to emit desires value when it occurs instead of raising observer's error callback (metasong). enter image description here

You might want to handle errors in inner Observable (i.e. inside switchMap), so errors thrown there, will not bubble up to main stream, that way the main stream continues after an error occurs, as demonstrated below:

  this.subscribe = timer(0, 30000)
    .pipe(
      switchMap(() => this.getData().pipe(catchError(x => of("handle error here"))))
      // catchError(...) don't handle error here
    )
    .subscribe();
Rafi Henig
  • 5,950
  • 2
  • 16
  • 36
  • Thanks for the thorough answer. I was not reaching the catchError bacause of HTTP_INTERCEPTORS – Guy E Aug 24 '20 at 07:09