Altamar Labs
Volver a Blog
arquitectura· 3 min de lectura

Diseñar para un runtime que puede morir en cualquier momento

Manifest V3 obliga a repensar cómo se mantiene vivo un estado que antes dábamos por garantizado. Lo que enseña sobre diseñar sistemas para entornos efímeros.

Durante años, escribir una extensión de navegador significaba asumir que tu script de fondo vivía tanto como el navegador estuviera abierto. Con Manifest V3, esa suposición desapareció: el service worker que reemplaza al background script puede terminarse en cualquier momento, típicamente a los pocos segundos de inactividad, y el navegador no avisa antes de hacerlo.

Esto no es una limitación arbitraria. Es la misma filosofía detrás de los workers serverless o los contenedores administrados por un orquestador: el runtime existe para ejecutar código, no para almacenar estado, y cualquier diseño que confunda esas dos cosas eventualmente falla de forma impredecible.

El problema concreto

Un service worker efímero rompe un patrón muy común: mantener una conexión persistente (un WebSocket, por ejemplo) para recibir eventos en tiempo real. Si el proceso que sostiene esa conexión puede morir en cualquier momento, la conexión muere con él, y reconectar tiene un costo, de tiempo, y a veces de eventos perdidos en la ventana entre la muerte y la reconexión.

La solución ingenua es "simplemente reconectar rápido". La solución real requiere dos preguntas distintas:

  • ¿Quién necesita mantenerse vivo, y por qué? Si la respuesta es "necesito recibir eventos en tiempo real desde un origen que yo no controlo", el service worker por sí solo no puede garantizarlo. Necesita ayuda de otra pieza del sistema que sí tenga garantías de vida más largas.
  • ¿Qué pasa con los eventos que llegan mientras el proceso está muerto? Si la respuesta es "se pierden", hay que decidir explícitamente si eso es aceptable. Si no lo es, se necesita un buffer en algún punto del sistema que sí sobreviva a la muerte del proceso.

La solución no es pelear contra el runtime

La estrategia que funciona no es intentar mantener el service worker vivo a la fuerza (hay técnicas para retrasar su muerte, pero son frágiles y dependen de comportamiento no garantizado). La estrategia que funciona es aceptar la efimeridad como parte del diseño:

  • Usar un documento auxiliar de vida más larga (un offscreen document, en el caso de extensiones) para sostener la conexión que realmente necesita persistir, dejando al service worker como simple despachador de eventos.
  • Introducir un buffer con expiración (TTL) para los eventos que llegan mientras el destino real, una pestaña, un campo del DOM, todavía no existe o no está listo para recibirlos.
  • Diseñar cada mensaje para que sea seguro procesarlo más de una vez, porque en un sistema con reinicios frecuentes, "exactamente una vez" es una garantía que casi nunca vale la pena perseguir.

La generalización

Cualquier sistema que hoy corre sobre infraestructura administrada por terceros, funciones serverless, workers en el borde, pods que un orquestador reinicia, enfrenta esta misma pregunta, aunque el mecanismo específico cambie. La habilidad de ingeniería no es aprender la API específica de un runtime efímero. Es interiorizar que el proceso es desechable, y el estado que importa no puede vivir únicamente dentro de él. Diseñar con esa premisa desde el principio es mucho más barato que descubrirla después de que algo crítico se pierda en producción.