Ir al contenido
AppsSDAR

Tiempo real con SSE: el aviso que nunca le llega al otro usuario

6 min de lectura Backend y seguridad

Las actualizaciones en vivo se prueban casi siempre con una sola cuenta abierta en dos pestañas. Todo se actualiza, la demo sale bien y la función se da por terminada. El problema aparece con dos personas distintas: los cambios que hace una no le llegan a la otra, o le llegan a quien no corresponde. Me pasó en más de un sistema, y la causa fue siempre el mismo atajo de diseño.

Server-Sent Events en dos líneas

SSE es la forma más simple de empujar eventos del servidor al navegador: una conexión HTTP que queda abierta y por la que el servidor escribe mensajes cuando quiere. No necesita librerías, se reconecta sola y atraviesa proxies sin problemas. Para notificaciones, contadores y bandejas, suele ser suficiente y más fácil de operar que WebSockets.

El atajo: emitir desde un interceptor

Para no escribir un evento en cada operación, es tentador poner un interceptor global: después de cada petición que modifica algo, emitir un evento de "cambió algo" por el canal SSE. Funciona muy bien para la persona que hizo la petición, porque el interceptor sabe quién es: es el usuario autenticado de esa petición.

Y ahí está el error. El interceptor solo conoce a quien hizo la petición. Si un agente asigna una conversación a otro agente, el evento se emite para el que asignó, no para quien recibió la asignación. Si un administrador cambia un permiso, lo ve el administrador, no el usuario afectado.

El caso peor: eventos cruzados

Una variante más grave aparece cuando el evento se envía por un canal compartido y se atribuye con los datos de la petición. Un sistema de presencia que muestra "quién está haciendo qué" puede terminar atribuyendo la acción de un usuario a otro conectado al mismo canal. No es solo un bug visual: puede mostrar información de una persona a otra.

La regla

Todo cambio que afecta a otra persona necesita un evento explícito dirigido a esa persona.

En la práctica, eso significa que las operaciones con destinatario distinto al autor emiten su propio evento, con el identificador del destinatario resuelto en el servidor. El interceptor puede seguir existiendo para refrescar la vista de quien actúa, pero no reemplaza los avisos a terceros.

Canales por destinatario

Cada conexión SSE se registra asociada a su usuario y, si aplica, a su organización. Emitir es elegir el destino: un usuario, todos los de una organización o todos los que miran un recurso concreto. Nunca se difunde a todas las conexiones y se deja que el navegador filtre, porque eso envía datos a quien no debe recibirlos aunque no los muestre.

Cómo probarlo de verdad

  • Dos cuentas distintas, en dos navegadores distintos o una ventana privada. Nunca dos pestañas de la misma sesión.
  • Para cada acción, preguntar a quién afecta además de a quien la hace, y verificar que esa persona lo ve.
  • Probar también el caso negativo: una tercera cuenta que no debe recibir el evento, no lo recibe.
  • Revisar la ventana entre despliegues: si el frontend nuevo espera un evento que el backend viejo aún no emite, la función parece rota durante unos minutos.

Un complemento necesario

Las conexiones SSE se cortan: el celular se bloquea, la red cambia, el servidor se reinicia. Al reconectar, el navegador no sabe qué se perdió. Por eso conviene que la pantalla vuelva a pedir el estado actual al reconectarse, en lugar de confiar en que recibió todos los eventos. El tiempo real acelera la experiencia, pero la consistencia la da poder reconstruir el estado en cualquier momento.