Cómo arreglar errores de Discourse Forum /message-bus o Long Polling

1. Problema

Cuando Discourse se configura con una CDN, ocurre un error común:

/message-bus/204234de907442e8b77e153786a58e5b/poll
Conexión fallida / tiempo de espera agotado / código de estado anormal

Impacto:

  • Las notificaciones fallan: El punto rojo (mensaje privado/respuesta nuevo) ya no aparece en tiempo real; las actualizaciones pueden llegar tarde o no llegar.

  • Las actualizaciones en tiempo real se rompen: Las nuevas publicaciones/me gusta/votos no se actualizan automáticamente; se requiere actualizar la página manualmente.

  • La experiencia del usuario empeora: Aparecen mensajes de “Conexión perdida”; las interacciones se retrasan.

  • Aumento de la carga del servidor: El frontend sigue intentando sondeos, lo que aumenta la presión sobre el origen.

Razón: Discourse utiliza sondeos largos (long polling) para mantener la comunicación en tiempo real. Muchas CDN imponen el almacenamiento en caché predeterminado, tiempos de espera reducidos, verificaciones de desafíos/firewall o almacenamiento en búfer en conexiones largas, lo que provoca interrupciones o respuestas almacenadas en caché que rompen el comportamiento en tiempo real.


2. Enfoque General (Estabilidad Primero)

  • Separación de dominios: Enrutar MessageBus a través de un dominio dedicado que se conecta directamente al origen.

  • Capa de proxy inverso (Nginx):

    • Habilitar CORS para /message-bus.
    • Deshabilitar el almacenamiento en búfer del proxy, relajar los tiempos de espera, prohibir explícitamente el almacenamiento en caché.
  • Capa CDN (si todavía se usa):

    • Configurar /message-bus/* con sin almacenamiento en caché, tiempo de espera extendido, sin desafíos de JS/CAPTCHA/limitación de velocidad, y paso de cookies/autorización.
    • O evitar la CDN por completo.

3. Pasos de Implementación

1) Configurar Variables de Entorno de Discourse

Edite app.yml (generalmente en /var/discourse/containers/app.yml) y agregue/modifique en env::

env:
  DISCOURSE_MESSAGE_BUS_REDIS_ENABLED: true
  DISCOURSE_LONG_POLLING_BASE_URL: "https://messagebus.example.com"

Aplique los cambios (despliegue oficial):

cd /var/discourse
./launcher rebuild app

Explicación:

  • DISCOURSE_LONG_POLLING_BASE_URL le dice al frontend que use el dominio MessageBus.
  • REDIS_ENABLED debe permanecer habilitado.

2) DNS y Certificado

  • Apunta messagebus.example.com directamente al origen, evitando la CDN (mejor práctica).
  • Configura un certificado HTTPS válido para el dominio.

3) Nginx (Dominio MessageBus) Proxy Inverso y CORS

Agregue o actualice lo siguiente en el bloque del servidor para messagebus.example.com:

location ^~ /message-bus {

    # (1) Manejar preflight CORS (OPTIONS)
    if ($request_method = OPTIONS) {
        add_header 'Access-Control-Allow-Origin' 'https://bbs.example.com' always;
        add_header 'Access-Control-Allow-Credentials' 'true' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With,discourse-deferred-track-view-topic-id,discourse-present,discourse-track-view,discourse-deferred-track-view,x-silence-logger,dont-chunk,x-shared-session-key' always;
        add_header 'Access-Control-Max-Age' 1728000 always;
        add_header 'Content-Type' 'text/plain; charset=UTF-8' always;
        add_header 'Content-Length' 0 always;
        return 204;
    }

    # (2) Proxy inverso a Discourse
    proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
    # o, si es independiente:
    # proxy_pass http://127.0.0.1:3000;

    # (3) Evitar encabezados CORS duplicados
    proxy_hide_header Access-Control-Allow-Origin;
    proxy_hide_header Access-Control-Allow-Credentials;
    proxy_hide_header Access-Control-Allow-Methods;
    proxy_hide_header Access-Control-Allow-Headers;
    proxy_hide_header Access-Control-Max-Age;

    # (4) CORS normal para solicitudes
    add_header 'Access-Control-Allow-Origin' 'https://bbs.example.com' always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With,discourse-deferred-track-view-topic-id,discourse-present,discourse-track-view,discourse-deferred-track-view,x-silence-logger,dont-chunk,x-shared-session-key' always;

    # (5) Configuración de estabilidad de sondeo largo
    proxy_read_timeout    120s;
    proxy_send_timeout    120s;
    proxy_connect_timeout 60s;

    proxy_buffering off;
    add_header X-Accel-Buffering no always;

    # (6) Prohibir explícitamente el almacenamiento en caché
    add_header Cache-Control "no-store, no-cache, must-revalidate" always;
}

:warning: Nota de seguridad: Si se usa Access-Control-Allow-Credentials: true, Origin no debe ser *; debe coincidir con el dominio exacto del foro.


4) Reglas de CDN (si el foro todavía está detrás de la CDN)

Recomendado: establece sin caché + tiempo de espera extendido + omisión de WAF/limitación de velocidad para estas rutas:

Ejemplo de expresión regular:

^/(session|login|message-bus|admin|u|users)(/|$)

Política:

  • Sin almacenamiento en caché del navegador/nodo (no-store/no-cache).
  • Tiempo de espera de upstream/lectura/inactividad ≥ 60–120s.
  • Deshabilitar desafío JS/CAPTCHA/gestión de bots.
  • Pasar cookies y encabezados de autorización (no eliminar).

4. Cómo Verificar el Éxito

1) Herramientas de Desarrollador del Navegador → Red

En la página del foro:

  • Observa /message-bus/…/poll.
  • La solicitud debería “colgarse” durante ~20–60s, luego devolver 200 (posiblemente vacío).
  • La siguiente solicitud de sondeo se activa automáticamente.

Comprueba los encabezados de respuesta:

  • Access-Control-Allow-Origin: https://bbs.example.com
  • Cache-Control: no-store
  • No Age, X-Cache: HIT, ni CF-Cache-Status: HIT (significa que no está en caché).

Problemas comunes:

  • Errores fijos de 10s/30s → tiempo de espera del borde/origen.
  • 504/524: tiempo de espera agotado.
  • 499: desconexión de la capa intermedia.
  • 403/401: bloqueo de WAF/autenticación.

2) Sonda Rápida desde Línea de Comandos (opcional)

Verifica la conectividad y los encabezados (no sondeos completos):

curl -I "https://messagebus.example.com/message-bus/health-check" \
  -H "Origin: https://bbs.example.com"

Nota: Los sondeos reales requieren contexto de sesión; esto solo verifica CORS y la conectividad.

1 me gusta