Como continuar catchError no cronômetro (rxjs)

Aug 23 2020

Tenho um serviço que é responsável por executar um httpClient.get a cada x segundos, usando um timer. Preciso que esse cronômetro comece a ser executado sempre que o serviço estiver ativo, portanto, o cronômetro é definido no construtor de serviço . No meu entendimento, a assinatura deve ser registrada no escopo do temporizador conforme abaixo (não quero alterá-la se não houver necessidade, a menos que esteja incorreta).

Todo o sistema está funcionando bem, desde que não haja erros \ exceções \ exceção erro 500 do servidor de backend. Agora, preciso de 2 coisas:

  1. Eu gostaria de pegar o erro sempre que houver um problema no servidor de backend.
  2. Gostaria que o observador continuasse correndo de acordo com os tempos do cronômetro (até o próximo tique), mesmo que haja uma exceção. Meu resultado final deve ser atingir o popUpAlert no componente sempre que houver exceção Veja meu código - este é o controlador webapi:
public IActionResult getSomeErrorAsTest()
{
    try
    {
        throw new Exception("Serer error");
    }
    catch(Exception ex)
    {
        return StatusCode(StatusCodes.Status500InternalServerError, new List<string>());
        //throw ex;
    }
}

Este é o serviço (suponha que os dados mudem em cada solicitação get - não há necessidade de implementar se realmente fizer):

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

O componente do consumidor:

export class MyComponent (private mySrv : MyService)
{
    getMyData()
    {
        let sub =this.mySrv.MyDataChanged.subscribe(result => doSomething(),
                                                    error=> popUpAlert());
    }
}

Respostas

2 RafiHenig Aug 23 2020 at 18:42

CatchErroro operador permite lidar com o erro, mas não altera a natureza do observável - o erro é a condição do terminal para determinado observável, portanto a emissão será interrompida. CatchErrorpermite emitir o valor dos desejos quando ocorre, em vez de aumentar o retorno de chamada de erro do observador ( metasong ).

Você pode querer lidar com erros no Observável interno (ou seja, interno switchMap), de modo que os erros gerados lá não borbulhem no fluxo principal, dessa forma o fluxo principal continua após a ocorrência de um erro, conforme demonstrado abaixo:

  this.subscribe = timer(0, 30000)
    .pipe(
      switchMap(() => this.getData().pipe(catchError(x => of("handle error here"))))
      // catchError(...) don't handle error here
    )
    .subscribe();