Implementación de Polling en Angular con Signals y rxResource

polling-angular-signals-rxresource

Como hacer polling en Angular con Signals y rxResource. Buenas practicas

Tiempo estimado de lectura: 4 min

Ideas clave

  • rxResource convierte Observables en señales gestionadas con limpieza automática.
  • Prefiere polling reactivo dentro del loader de rxResource (timer + switchMap).
  • Implementa retry/backoff, pausa con Page Visibility API y evita polling agresivo en móviles.
  • Usa switchMap para cancelar peticiones lentas y shareReplay para cache compartida.

Como hacer polling en Angular con Signals y rxResource. Si esa es la pregunta que te trajo hasta aquí, perfecto: vamos directo al punto. Polling no es magia; es un patrón con trampas si no lo diseñas pensando en resiliencia, eficiencia y vida útil de la UI. Aquí tienes cómo hacerlo bien, con ejemplos prácticos y criterios que realmente importan.

Polling no es solo hacer peticiones cada X segundos: es hacerlo con criterio.

Resumen rápido (lectores con prisa)

Qué es: rxResource convierte Observables en señales gestionadas (valor, carga, error, reload).

Cuándo usar: dashboards y estados donde 2–30s de retraso son aceptables; no para latencia < 1s.

Por qué importa: limpieza automática, cancelación de peticiones y patrón más seguro que intervalos manuales.

Cómo: preferible encapsular polling dentro del loader con timer + switchMap, añadir retry/backoff y pausar con Page Visibility API.

¿Qué es rxResource y por qué importa para el polling?

rxResource (paquete: @angular/core/rxjs-interop) convierte un Observable en una señal gestionada: expone .value(), .isLoading(), .error() y .reload(). Maneja la limpieza de suscripciones automáticamente cuando el componente se destruye, lo que reduce significativamente el boilerplate y las fugas de memoria. Documentación.

Eso cambia las reglas del juego: el loader de un resource puede devolver un Observable que emita múltiples valores (ideal para polling). En lugar de gestionar intervalos manuales y ngOnDestroy, encapsulas la lógica reactiva en el resource.

Estrategias válidas: cuándo usar cada una

Hay dos patrones útiles: el imperativo (reload) y el declarativo (loader periódico). Usa el primero cuando el usuario debe controlar el ciclo (pausar/reanudar). Prefiere el segundo como opción por defecto: es más limpia y segura.

1) Polling imperativo con reload()

Útil si la UI ofrece control explícito (botón pausa).

// patrón simplificado
const dataResource = rxResource({ loader: () => http.get('/api/status') });

const id = window.setInterval(() => dataResource.reload(), 5000);
// clearInterval(id) al destruir/comportamiento de pausa

Ventaja: control directo. Desventaja: gestión manual del ciclo de vida y riesgo de olvidarte de limpiar el intervalo.

2) Polling reactivo dentro del loader (recomendado)

Encapsula todo en el loader. El resource escucha un Observable que emite periódicamente.

import { timer, EMPTY, merge, of, fromEvent } from 'rxjs';
import { switchMap, map, retry, catchError } from 'rxjs/operators';

dataResource = rxResource({
  request: () => ({ interval: pollIntervalSignal() }),
  loader: ({ request }) => {
    const visibility$ = merge(
      of(document.visibilityState === 'visible'),
      fromEvent(document, 'visibilitychange').pipe(map(() => document.visibilityState === 'visible'))
    );

    return visibility$.pipe(
      switchMap(visible =>
        visible
          ? timer(0, request.interval).pipe(
              switchMap(() => http.get('/api/metrics')),
              retry({ count: 3, delay: 1000 }),
              catchError(() => EMPTY) // mantiene vivo el stream ante errores transitorios
            )
          : EMPTY
      )
    );
  }
});

Beneficios prácticos: limpieza automática, cancelación de peticiones lentas gracias a switchMap, y pause automático con Page Visibility API.

Referencia útil sobre retry. Página sobre Page Visibility API (MDN).

Buenas prácticas obligatorias (no opcionales)

  • Usa switchMap para evitar race conditions. Si una petición tarda más que el intervalo, cancelas la anterior.
  • Implementa backoff para errores persistentes. No bombardees un servidor con 500s: retryWhen + delay exponencial.
  • Pausa el polling cuando la pestaña está oculta (Page Visibility API) o cuando el dispositivo entra en modo bajo consumo.
  • Evita polling agresivo en dispositivos móviles. Considera un throttle dinámico o reducir frecuencia en redes móviles.
  • Agrupa requests cuando sea posible (batching/forkJoin) para reducir overhead.
  • Usa cache + TTL (shareReplay(1) con invalidación) si la misma petición la hacen múltiples componentes.
  • Supervisión: expón métricas de errores/latencia en logs para detectar piezas rotas del polling.

Testing y observabilidad

  • Testea con fakeAsync y tick() para simular intervalos en unit tests.
  • Mockea rxResource utilizando proveedores en TestBed para controlar emisiones.
  • Registra fallos y frecuencia de reintentos; si ves un patrón de reintentos masivos, cambia a backoff más agresivo o al modo “degraded”.

Cuándo no usar polling

No uses polling si necesitas latencia < 1s o alta frecuencia. Para actualizaciones en tiempo real, usa WebSockets o SSE. Polling sigue siendo válido para dashboards, contadores y estados donde 2–30s de retraso son aceptables.

Guías de alternativas: WebSockets / SSE.

Resumen práctico (lista rápida)

  • Preferible: implementar polling dentro del loader de rxResource con timer + switchMap.
  • Añadir: retry/backoff, Page Visibility API para pausar, shareReplay si es necesario.
  • Imperativo (reload) sólo si la UX necesita control manual.
  • Evitar: polling sin control de errores o sin pausa para pestañas ocultas.

Fuentes

FAQ

¿Qué es exactamente rxResource?

Respuesta: rxResource convierte un Observable en una señal gestionada que expone métodos como .value(), .isLoading(), .error() y .reload(), y gestiona la limpieza de suscripciones al destruirse el componente.

¿Por qué preferir el polling dentro del loader?

Respuesta: Porque encapsula la lógica reactiva, permite limpieza automática, usa operadores como switchMap para cancelar peticiones y facilita pausar con APIs como Page Visibility.

¿Cuándo usar reload() en lugar de polling declarativo?

Respuesta: Usa reload() cuando la UX requiere control manual del ciclo (por ejemplo, un botón de pausa/reanudar). Para la mayoría de casos, el loader periódico es más seguro.

¿Cómo manejo errores transitorios sin romper el stream?

Respuesta: Usa operadores como retry o retryWhen con backoff y catchError retornando EMPTY para mantener vivo el stream ante errores transitorios.

¿Cómo pauso el polling cuando la pestaña está oculta?

Respuesta: Observa document.visibilityState o escucha el evento visibilitychange y condiciona el stream para emitir solo cuando la pestaña esté visible.

¿Es el polling adecuado en móviles?

Respuesta: Con precaución: evita frecuencias agresivas, reduce la tasa en redes móviles y considera estrategias de throttling dinámico o degradado.

¿Qué alternativas usar si necesito latencia menor a 1s?

Respuesta: Emplea WebSockets o Server-Sent Events para actualizaciones en tiempo real; el polling no es adecuado para exigencias de latencia muy baja.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *