Intento hacer ping a una URL/API continua con rxjs.
Mi primer intento fue:
timer(3000, 2000) .pipe(mergeMap(() => this._http.get(environment.pingUrl))) .subscribe(res => console.log(res), err => console.log(err))Pero cuando no se puede acceder a la URL, nunca obtengo una respuesta. Así que decido establecer un tiempo de espera:
timer(3000, 2000) .pipe(mergeMap(() => this._http.get(environment.pingUrl).pipe(timeout(5000))) .subscribe(res => console.log(res), err => console.log(err))Ahora obtengo el primer tiempo de espera/respuesta cuando no se puede acceder a la API, pero luego parece que el tiempo de espera activa una cancelación de suscripción para el temporizador y no hay más respuesta. No tengo idea de evitar que esto se dé de baja.
Por lo que entiendo, le gustaría hacer ping a una API continuamente y continuar cuando no se pueda acceder a esta API.
El problema que tiene es que, cuando la API falla, el observable se completa y no se activará nuevamente.
Deberá usar reintentar o reintentar cuando
y simplemente hacer
timer(2000, 3000) .pipe( mergeMap(() => this._http.get(environment.pingUrl)), timeout(5000), retryWhen(() => timer(3000)) ) .subscribe( (res) => console.log(res), (err) => console.log(err) );ejemplo: https://stackblitz.com/edit/rxjs-playground-test-mgppcj
Asegúrese de darse de baja de este observable en algún momento.
En RxJS, los Observables tienen tres tipos de emisiones.
next : Un valor en el vapor, puede haber de 0 a arbitrariamente muchos de estoserror : Una emisión terminal. Esta instancia del observable tiene un error y está cerrada. Nunca podrá volver a emitir.complete : Una emisión terminal. Esta instancia del observable está hecha y cerrada. Nunca volverá a emitir. Notará que una instancia de un observable nunca puede emitir más de un error o una emisión complete , pero cualquier observable se puede ejecutar (o reiniciar/reintentar) cualquier cantidad de veces. Cada vez que te suscribes o algún operador se suscribe por ti, creas una nueva instancia de un observable.
Dado que los observables nunca pueden emitir después de un error, la única forma de emitir errores mientras continúa es capturar la emisión de error y convertirla en una next emisión.
En este ejemplo, cada vez que la fuente tiene errores observables, le digo a catchError que se vuelva a suscribir a la fuente.
{value: }{error: } .Me ocupo de estos errores detectados simplemente imprimiéndolos en la consola, pero es probable que desee hacer algo mejor que eso :)
timer(3000, 2000).pipe( mergeMap(_ => this._http.get(environment.pingUrl)), map(value => ({value})), timeout({each: 5000}), catchError((error, src) => { // Only catch/handle TimeoutError if(error instanceof TimeoutError){ return src.pipe(startWith({error})); } else { return throwError(() => error); } }) ).subscribe({ next: emitted => { if("error" in emitted){ // Found an error! In this case, we only handled // TimeoutErrors, so that'll appear here as a next // emission. The observable is still running. console.log("Caught an error: ", emitted.error); }else{ // got a result! console.log(emitted.value); } }, // All other errors appear here and are error emissions, // so they're terminal. This observable is closed error: err => console.log("Uncaught error: ", err), // The complete emission is also terminal. This // observable is now closed. complete: () => console.log("Complete") });