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.
- Dominio del foro (a través de CDN): https://bbs.example.com
- Dominio MessageBus (sin CDN): https://messagebus.example.com
-
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;
}
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.