Ir al contenido

Solución de problemas de WebSocket

Diagnostica y resuelve problemas comunes del WebSocket de Rhombus: fallos de conexión, errores de STOMP, heartbeats perdidos, problemas de autenticación y eventos descartados.

En esta página

Esta guía cubre los problemas comunes al trabajar con conexiones WebSocket de Rhombus y cómo resolverlos.

Problemas de conexión

No se puede conectar (conexión rechazada)

Síntomas: el handshake de WebSocket falla de inmediato con un error de conexión.

Causas posibles:

  • Un firewall bloquea las conexiones salientes en el puerto 8443
  • Hostname incorrecto

Soluciones:

  1. Verifica el acceso saliente a ws.rhombussystems.com en el puerto 8443:
    bash
    # Test connectivity
    curl -v https://ws.rhombussystems.com:8443/websocket
    
    # Test TCP connectivity directly
    nc -zv ws.rhombussystems.com 8443
  2. Comprueba que tu red/firewall permita WSS saliente en el puerto 8443
  3. Si estás detrás de un proxy corporativo, asegúrate de que se permitan las solicitudes de actualización (upgrade) de WebSocket

HTTP 401 Unauthorized

Síntomas: el handshake de WebSocket falla con HTTP 401. El errorCode del cuerpo JSON indica el motivo.

Causas posibles:

  • UNAUTHENTICATED: no llegó ninguna credencial al servidor. Falta x-auth-scheme o está mal escrito, la clave de API o el token de OAuth se enviaron como parámetro de query (solo un token federado puede ir ahí), o el esquema es de certificado (api, partner-api), que esta conexión no acepta
  • INVALID_CREDENTIAL: la clave o el token están mal formados, son desconocidos (por ejemplo, una clave de API eliminada) o son de la otra región
  • CREDENTIAL_EXPIRED o CREDENTIAL_REVOKED: la clave o el token expiraron, o se revocaron (por ejemplo, un token de OAuth cuyo grant se revocó). Un token federado también deja de funcionar cuando se elimina o revoca la clave, el grant de OAuth o la sesión que lo generó
  • CERTIFICATE_MISMATCH: una clave de certificado enviada con api-token

Soluciones:

  1. Envía el esquema y la credencial como indica Autenticación de WebSocket: x-auth-scheme=api-token con la clave en el encabezado x-auth-apikey, Authorization: Bearer <token> para un access token de OAuth, o x-auth-scheme=federated-token&x-auth-ft=<token> para un token federado
  2. Verifica que la clave funcione con la API REST de la misma región:
    bash
    curl -X POST https://api2.rhombussystems.com/api/org/getOrgV2 \
      -H "x-auth-scheme: api-token" \
      -H "x-auth-apikey: YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{}'
  3. Reemplaza una credencial expirada o revocada: crea una clave nueva, renueva el token de OAuth o genera un token federado nuevo

HTTP 403 Forbidden

Síntomas: el handshake de WebSocket falla con HTTP 403. La credencial es válida pero no está permitida en esta conexión; el errorCode del cuerpo JSON indica el motivo.

Causas posibles:

  • PERMISSION_REQUIRED: una credencial de partner sin el encabezado x-auth-org, o un access token de OAuth cuyo grant no incluye el scope read (la respuesta también incluye WWW-Authenticate: Bearer error="insufficient_scope", scope="read")
  • PARTNER_CLIENT_ACCESS_DENIED: una credencial de partner sin autorización para la organización indicada en x-auth-org
  • DOMAIN_NOT_ALLOWED: un token federado generado con domain, abierto desde una página cuyo Origin es otro origen

Soluciones:

  1. Si usas una credencial de partner, envía el UUID de la organización destino en el encabezado x-auth-org (el servidor lee x-auth-org de los encabezados de la solicitud, no de la cadena de query):
   Encabezado: x-auth-org: CLIENT_ORG_UUID
   URL:        wss://ws.rhombussystems.com:8443/websocket?x-auth-scheme=api-token
  1. En una app OAuth, solicita el scope read cuando el usuario la autorice
  2. Genera los tokens federados con el origen exacto de tu página como domain (esquema, host y puerto), o sin domain

La autenticación basada en certificados no funciona

Síntomas: la conexión falla al usar una clave de certificado mTLS: 401 UNAUTHENTICATED con el esquema api, o 401 CERTIFICATE_MISMATCH cuando la clave de certificado se envía con api-token.

Causa: el WebSocket de eventos no acepta claves de certificado.

Solución: conéctate con una clave de API estándar (Tipo de autenticación Token de API), un access token de OAuth o un token federado. Las claves de certificado funcionan en la API REST.

Problemas del protocolo STOMP

El frame CONNECTED nunca se recibe

Síntomas: el WebSocket se conecta correctamente, pero no se recibe ninguna respuesta STOMP CONNECTED después de enviar CONNECT.

Causas posibles:

  • Frame STOMP CONNECT mal formado
  • Falta el terminador nulo (\x00)
  • Valor de accept-version incorrecto

Soluciones:

  1. Verifica que tu frame incluya el terminador de byte nulo:
    python
    # Correct
    frame = "CONNECT\naccept-version:1.2\nheart-beat:10000,10000\n\n\x00"
    
    # Wrong - missing \x00
    frame = "CONNECT\naccept-version:1.2\nheart-beat:10000,10000\n\n"
  2. Asegúrate de que haya una línea vacía (\n\n) entre los encabezados y el cuerpo
  3. Usa accept-version:1.2 (no 1.0 ni 1.1)

No se reciben mensajes después de suscribirse

Síntomas: la conexión y la suscripción se realizan correctamente, pero no llegan frames MESSAGE.

Causas posibles:

  • El rol de la credencial no cubre los dispositivos o ubicaciones que generan los eventos. Los eventos fuera del rol se descartan sin error, incluidas las alertas de políticas: una alerta solo se entrega a un rol que tiene acceso a su dispositivo o ubicación.
  • No ocurren eventos en la organización
  • Frame de suscripción mal formado

Un UUID de organización incorrecto no produce silencio: al suscribirte al tópico de otra organización recibes un frame STOMP ERROR y el servidor cierra el socket con el código 1002.

Soluciones:

  1. Revisa el rol en la Consola de Rhombus (para una clave de API, el rol de la clave; para un token de OAuth, el rol del usuario; para un token federado, el rol de la credencial que lo generó): un rol con acceso completo recibe todos los eventos de la organización. Consulta Qué recibe una conexión.
  2. Verifica el UUID de tu organización llamando a la API REST:
    bash
    curl -X POST https://api2.rhombussystems.com/api/org/getOrgV2 \
      -H "x-auth-scheme: api-token" \
      -H "x-auth-apikey: YOUR_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{}'
  3. Dispara un evento de prueba (por ejemplo, ajusta una configuración de cámara) para confirmar que el flujo está activo
  4. Verifica que el formato del tópico sea exactamente /topic/change/{orgUuid} sin barras finales ni espacios

Problemas de estabilidad de la conexión

La conexión se cae cada ~30 segundos

Síntomas: la conexión WebSocket se cierra después de aproximadamente 30 segundos de inactividad.

Causa: no se están enviando heartbeats.

Solución: implementa el emisor de heartbeats que envía \n cada 10 segundos:

python
import threading

def heartbeat_sender(ws, stop_event):
    while not stop_event.is_set():
        ws.send("\n")
        stop_event.wait(10)

stop = threading.Event()
thread = threading.Thread(target=heartbeat_sender, args=(ws, stop), daemon=True)
thread.start()

La conexión se cierra con el código 1008

Síntomas: el servidor envía un frame STOMP ERROR y cierra la conexión con el código 1008.

Causa: la credencial se eliminó o revocó, o su rol cambió, mientras la conexión estaba abierta. El servidor vuelve a verificar la credencial aproximadamente una vez por minuto, así que esto ocurre en 60 segundos o menos después del cambio. Revocar un grant de OAuth, o la clave o la sesión que generó un token federado, tiene el mismo efecto.

Solución: revisa la credencial antes de reconectarte. Después de un cambio de rol, una conexión nueva aplica el nuevo rol; después de una eliminación o revocación, todo handshake con esa credencial falla con 401, así que reemplázala en lugar de reintentar.

La conexión se cae de forma intermitente

Síntomas: la conexión funciona durante un tiempo y luego se cae de forma impredecible.

Causas posibles:

  • Inestabilidad de la red
  • Mantenimiento del lado del servidor
  • Timeout del balanceador de carga

Soluciones:

  1. Implementa la reconexión automática con backoff:
    python
    while True:
        try:
            run_websocket_monitor()
        except ConnectionError:
            print("Reconnecting in 5 seconds...")
            time.sleep(5)
  2. Registra los motivos de desconexión para identificar patrones
  3. Monitorea la recepción de heartbeats para detectar conexiones muertas de forma proactiva

Alto uso de memoria con el tiempo

Síntomas: la memoria de la aplicación crece de forma constante mientras está conectada.

Causas posibles:

  • Los eventos se acumulan en una cola sin límite
  • No se procesan los mensajes con suficiente rapidez

Soluciones:

  1. Usa buffers de mensajes con límite:
    python
    # Use a bounded queue
    from queue import Queue
    event_queue = Queue(maxsize=1000)
  2. Procesa los eventos de forma asíncrona para evitar la contrapresión (backpressure)
  3. Descarta o registra los eventos si la cola de procesamiento está llena

Problemas de procesamiento de eventos

Eventos faltantes

Síntomas: algunos eventos que aparecen en la consola de Rhombus no aparecen en el flujo de WebSocket.

Causas posibles:

  • El rol de la credencial no cubre esos dispositivos o ubicaciones (los eventos fuera del rol se descartan sin error)
  • El rol es limitado y el tipo de entidad no tiene verificación de acceso: esos tipos solo llegan a roles de acceso completo
  • El filtrado de eventos es demasiado agresivo
  • Una breve desconexión causó la pérdida de eventos
  • El evento ocurrió antes de que se estableciera la suscripción

Soluciones:

  1. Habilita temporalmente todos los eventos para verificar el flujo:
    python
    # Don't filter by entity type
    if frame["command"] == "MESSAGE":
        print(json.loads(frame["body"]))
  2. Los eventos de WebSocket son solo en tiempo real. Para eventos históricos, usa la API REST
  3. Asegúrate de que SUBSCRIBE se envíe antes de esperar eventos

JSON mal formado en el cuerpo del evento

Síntomas: json.loads() falla con el cuerpo de MESSAGE.

Causas posibles:

  • El parser de frames no separa correctamente el cuerpo de los encabezados
  • Bytes nulos o espacios en blanco adicionales en el cuerpo

Soluciones:

  1. Elimina los bytes nulos antes de parsear:
    python
    body = frame["body"].strip("\x00").strip()
    payload = json.loads(body)
  2. Verifica que tu parser de frames divida en \n\n correctamente (solo la primera ocurrencia)

Herramientas de depuración

Habilitar el registro de frames sin procesar

Agrega registro (logging) para ver exactamente qué se envía y se recibe:

python
import logging

logging.basicConfig(level=logging.DEBUG)

# In your message loop:
raw = ws.recv()
logging.debug(f"Received: {repr(raw)}")

Probar con websocat

Usa wscat para interactuar manualmente con el endpoint de WebSocket:

bash
# Install
npm install -g wscat

# Connect (note: wscat does not support custom headers natively,
# so use a tool like websocat for full header support)
websocat -H "x-auth-apikey: YOUR_TOKEN" \
  "wss://ws.rhombussystems.com:8443/websocket?x-auth-scheme=api-token"

# Then manually type STOMP frames:
CONNECT
accept-version:1.2
heart-beat:10000,10000

^@

Monitor de la CLI de Rhombus

Usa la CLI de Rhombus para verificar que tu cuenta y el endpoint de WebSocket funcionen:

bash
# Install the CLI (macOS/Linux)
brew install RhombusSystems/tap/rhombus

# Authenticate
rhombus login

# Test WebSocket monitoring
rhombus monitor --all-events --json

Si la CLI funciona pero tu código no, compara los parámetros de conexión que usa tu código con el comportamiento de la CLI. Consulta la documentación de la CLI de Rhombus para conocer todos los detalles de instalación y uso.

Cómo obtener ayuda

Si has probado los pasos anteriores y sigues experimentando problemas:

  1. Consulta el registro de cambios para ver los cambios recientes
  2. Contacta al Soporte de Rhombus en support@rhombus.com con:
    • El UUID de tu organización
    • El mensaje de error o el código de estado HTTP
    • La marca de tiempo del intento de conexión fallido
    • Tu lenguaje de cliente y la versión de la biblioteca de WebSocket