1. Problema
Quando o Discourse é configurado com uma CDN, ocorre um erro comum:
/message-bus/204234de907442e8b77e153786a58e5b/poll
Conexão falhou / tempo limite esgotado / código de status anormal
Impacto:
-
Falha nas notificações: O ponto vermelho (nova mensagem privada/resposta) não aparece mais em tempo real; as atualizações podem chegar atrasadas ou não chegar.
-
Quebra de atualizações em tempo real: Novas postagens/curtidas/votos não são atualizados automaticamente; é necessária a atualização manual da página.
-
Queda na experiência do usuário: Mensagens de “Conexão perdida” aparecem; as interações atrasam.
-
Aumento da carga do servidor: O frontend continua tentando novas pesquisas, adicionando pressão à origem.
Motivo: O Discourse usa long polling para manter a comunicação em tempo real. Muitas CDNs impõem cache padrão, tempos limite reduzidos, verificações de desafio/firewall ou buffering em conexões longas, causando interrupções ou respostas em cache que quebram o comportamento em tempo real.
2. Abordagem Geral (Estabilidade Primeiro)
-
Separação de domínios: Roteie o MessageBus através de um domínio dedicado que se conecta diretamente à origem.
- Domínio do Fórum (via CDN): https://bbs.example.com
- Domínio do MessageBus (sem CDN): https://messagebus.example.com
-
Camada de proxy reverso (Nginx):
- Habilite CORS para /message-bus.
- Desabilite o buffering do proxy, relaxe os tempos limite, proíba explicitamente o cache.
-
Camada de CDN (se ainda usada):
- Configure /message-bus/* com sem cache, tempo limite estendido, sem desafios de JS/CAPTCHA/limitação de taxa e passagem de cookies/autorização.
- Ou ignore a CDN completamente.
3. Passos de Implementação
1) Configurar Variáveis de Ambiente do Discourse
Edite o app.yml (geralmente em /var/discourse/containers/app.yml) e adicione/modifique em env::
env:
DISCOURSE_MESSAGE_BUS_REDIS_ENABLED: true
DISCOURSE_LONG_POLLING_BASE_URL: "https://messagebus.example.com"
Aplique as alterações (implantação oficial):
cd /var/discourse
./launcher rebuild app
Explicação:
- DISCOURSE_LONG_POLLING_BASE_URL informa ao frontend para usar o domínio do MessageBus.
- REDIS_ENABLED deve permanecer habilitado.
2) DNS e Certificado
- Aponte messagebus.example.com diretamente para a origem, ignorando a CDN (melhor prática).
- Configure um certificado HTTPS válido para o domínio.
3) Nginx (Domínio MessageBus) Proxy Reverso e CORS
Adicione ou atualize o seguinte no bloco do servidor para messagebus.example.com:
location ^~ /message-bus {
# (1) Lidar com o 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 reverso para Discourse
proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
# ou, se standalone:
# proxy_pass http://127.0.0.1:3000;
# (3) Prevenir cabeçalhos 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 requisições
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) Configurações de estabilidade de long polling
proxy_read_timeout 120s;
proxy_send_timeout 120s;
proxy_connect_timeout 60s;
proxy_buffering off;
add_header X-Accel-Buffering no always;
# (6) Proibir explicitamente o cache
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
}
Nota de segurança: Se Access-Control-Allow-Credentials: true for usado, Origin não pode ser *; deve corresponder ao domínio exato do fórum.
4) Regras da CDN (se o fórum ainda estiver atrás da CDN)
Recomendado: defina sem cache + tempo limite estendido + ignorar WAF/limitação de taxa para esses caminhos:
Exemplo de Regex:
^/(session|login|message-bus|admin|u|users)(/|$)
Política:
- Sem cache do navegador/nó (no-store/no-cache).
- Tempo limite de upstream/leitura/ocioso ≥ 60–120s.
- Desabilite desafio de JS/CAPTCHA/gerenciamento de bots.
- Passe cookies e cabeçalhos de autorização (não remova).
4. Como Verificar o Sucesso
1) Ferramentas do Desenvolvedor do Navegador → Rede
Na página do fórum:
- Observe /message-bus/…/poll.
- A requisição deve “pendurar” por ~20–60s, depois retornar 200 (possivelmente vazio).
- A próxima requisição de poll é acionada automaticamente.
Verifique os cabeçalhos de resposta:
- Access-Control-Allow-Origin: https://bbs.example.com
- Cache-Control: no-store
- Sem Age, X-Cache: HIT ou CF-Cache-Status: HIT (significa que não foi armazenado em cache).
Problemas comuns:
- Erros fixos de 10s/30s → tempo limite da borda/origem.
- 504/524: tempo limite esgotado.
- 499: desconexão da camada intermediária.
- 403/401: bloqueio de WAF/autenticação.
2) Teste Rápido via Linha de Comando (opcional)
Verifique a conectividade e os cabeçalhos (não a pesquisa completa):
curl -I "https://messagebus.example.com/message-bus/health-check" \
-H "Origin: https://bbs.example.com"
Observação: As pesquisas reais exigem contexto de sessão; isso apenas verifica CORS e conectividade.