11 puntos por GN⁺ 2025-04-13 | 3 comentarios | Compartir por WhatsApp
  • WebSocket es útil para la comunicación en tiempo real, pero no siempre es necesario, y las alternativas basadas en HTTP pueden ser más simples y estables
  • En el procesamiento transaccional, la gestión de conexiones y la complejidad del servidor, WebSocket puede generar una sobrecarga excesiva
  • Con HTTP Streaming y una librería como eventkit, es posible sincronizar estado y procesar eventos en tiempo real sin usar WebSocket

Qué es WebSocket

  • WebSocket es una tecnología que abre un canal de comunicación bidireccional persistente entre cliente y servidor
  • La conexión se inicia a través de HTTP, pero después la comunicación ocurre mediante un protocolo distinto
  • Se usa con frecuencia para implementar aplicaciones en tiempo real, y es útil porque permite comunicación en ambas direcciones

Los mensajes de WebSocket no son transaccionales

  • WebSocket no garantiza una relación directa entre solicitud y respuesta
  • Los comandos de cambio de estado y los mensajes con sus resultados pueden llegar mezclados dentro del mismo flujo
  • Por ejemplo, si un cliente cambia un estado y ocurre un error, puede ser difícil saber a qué comando corresponde ese error
  • Una forma de resolverlo es incluir un requestId para vincular comandos y respuestas, pero esto aumenta la complejidad y el costo de mantenimiento
  • Es más simple enviar los comandos de forma transaccional usando HTTP y dejar WebSocket solo para difundir cambios de estado
  • Es posible separar el envío por medio de solicitudes HTTP y la recepción por medio de WebSocket u otro mecanismo de streaming

La dificultad de gestionar el ciclo de vida de una conexión WebSocket

  • Al usar WebSocket, hay que manejar directamente el inicio, cierre, errores y reconexión de la conexión
  • Un ejemplo de manejo básico en el navegador incluye eventos de apertura de conexión, recepción de mensajes, errores y cierre de conexión
  • También se necesita lógica adicional como reconexión, buffering de mensajes y backoff exponencial
  • En cambio, con HTTP el inicio y el fin están claramente definidos por cada solicitud, por lo que la implementación es más simple
  • Gestionar un ciclo de vida complejo solo se justifica cuando realmente hay una razón clara para usar WebSocket

Aumento de la complejidad del código del servidor

  • WebSocket requiere procesar solicitudes de actualización de HTTP, lo que exige lógica adicional de handshake
  • Hay que validar encabezados especiales como Sec-WebSocket-Key y devolver correctamente los encabezados de respuesta
  • Después de establecer la conexión WebSocket, se debe mantener un estado continuo de recepción y envío de mensajes, y también pueden surgir problemas como el manejo de frames parciales
  • En comparación con usar solo HTTP, depurar y manejar errores se vuelve más difícil
  • Aunque algunos frameworks abstraen parte del proceso, la complejidad base sigue existiendo

Alternativa: HTTP Streaming

  • HTTP es un protocolo que originalmente ya soporta streaming, por lo que puede enviar flujos de datos en tiempo real en lugar de archivos completos
  • Es posible reemplazar con HTTP streaming solo la parte receptora que normalmente cumpliría WebSocket
  • Se pueden procesar actualizaciones de estado en forma de flujo usando generadores asíncronos
  • Flujo del lado del servidor
    • Las actualizaciones de estado se realizan dentro de la función que procesa los comandos
    • Los clientes conectados reciben los nuevos valores mediante generadores cada vez que aparecen
    • Los comandos de cambio de estado se envían por HTTP POST y el flujo en tiempo real se suscribe con una solicitud GET
  • Flujo del lado del cliente
    • Recepción de datos en tiempo real mediante Fetch API y Stream Reader
    • Decodificación del texto y actualización de la UI
  • Con esta estructura es posible implementar sincronización de estado en tiempo real sin WebSocket

Bonus: introducción a la librería eventkit

  • eventkit es una librería que facilita construir y observar flujos asíncronos
  • Es similar a RxJS, pero mejora la gestión de efectos secundarios y está diseñada con base en generadores
  • Si se envían actualizaciones de estado al flujo, el cliente puede recibirlas en tiempo real
  • Con Stream y AsyncObservable, se puede implementar de forma sencilla tanto en el servidor como en el cliente
  • Uso de eventkit en el servidor
    • Los cambios de estado se hacen push al Stream y los clientes se suscriben a ese flujo
  • Uso de eventkit en el cliente
    • Se reciben los datos del flujo, se decodifican y luego se actualiza la UI
  • También se ofrecen el repositorio oficial de GitHub y una guía de HTTP Streaming

GitHub: https://github.com/hntrl/eventkit

3 comentarios

 
[Este comentario fue ocultado.]
 
[Este comentario fue ocultado.]
 
GN⁺ 2025-04-13
Opiniones en Hacker News
  • No creo que el streaming por HTTP haya sido diseñado pensando en este patrón. El streaming por HTTP sirve para dividir datos grandes en partes. Si usas streaming como un mecanismo pub/sub, podrías arrepentirte. Los intermediarios HTTP no esperan este patrón de tráfico (NGINX, CloudFlare, etc.). Parece que cada vez que se corte la conexión WiFi, la API fetch va a fallar la solicitud con un error

    • Muchas veces no se necesitan WebSockets. Los eventos enviados por el servidor (SSE) son una solución más simple. Es una pena que SSE no haya recibido más atención
  • Enviar un RequestID al servidor para obtener un ciclo de solicitud/respuesta no es raro ni excesivo. En una app seria, siempre vale la pena tener una API como send(message).then(res => ...)

    • Las solicitudes de upgrade son confusas. Es molesto que el servidor WebSocket quede embebido dentro del servidor HTTP y no se integre bien
    • En lugar de reutilizar middleware que lee headers['authorization'] en el servidor WebSocket, hay que acceder a un objeto connectionParams que pretende ser un encabezado de solicitud
    • La API de WebSocket en el navegador es más cómoda de manejar que EventSource
  • El streaming de video hace que el cliente solicite chunks por rango, no usa una sola conexión HTTP

  • Es mejor usar SSE en lugar de EventKit

  • En el POC voy a usar el envío tradicional de formularios HTTP. No hace falta nada más

    • El arquitecto insiste en que se necesitan WebSockets
    • El POC no necesita XHR ni WebSockets. Es un flujo de compra secuencial
    • Al final terminan entregando WebSockets innecesarios
  • El problema con HTTP2 es que el server push fue agregado encima del protocolo existente. HTTP es un protocolo de transferencia de recursos, así que agrega sobrecarga innecesaria. El objetivo principal de HTTP2 es que el servidor haga push anticipado de archivos/recursos al cliente para reducir la latencia de ida y vuelta

    • WebSockets es un protocolo más simple diseñado para comunicación bidireccional. Con una sola conexión es más fácil controlar el flujo de datos. También facilita la gestión de estado y la recuperación ante pérdida de conexión. La autenticación y el control de acceso se vuelven más simples
  • WebSockets no envía como stream, sino como datagramas (paquetes). La API de WebSockets de las librerías JavaScript no puede manejar backpressure y no puede manejar todos los errores. Hay que tener cuidado si se quiere usar como un stream TCP

  • Me arrepentí después de desplegar WebSockets en producción. Había problemas como que NGINX cerraba la conexión después de 4/8 horas, o que el navegador no se reconectaba después de salir del modo de suspensión. Si es posible, conviene evitar WebSockets y las conexiones de larga duración

  • Existe una percepción idealizada sobre WebSockets. Hay una tendencia a querer usar WebSockets para casos de uso de streaming/tiempo real. WebSockets hace que se pierda la simplicidad y las ventajas de las herramientas HTTP. La solución para cambios de servidor por streaming es h2/h3 y SSE. Si se puede agrupar hasta un máximo de 0.5 req/s por cliente, no hacen falta WebSockets

  • Quienes estén interesados en el streaming por HTTP deberían revisar Braid-HTTP. Extiende de forma elegante HTTP con streaming de eventos para ofrecer un potente protocolo de sincronización de estado