Como Corrigir Erros de Discourse Forum /message-bus ou Long Polling

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.

  • 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;
}

:warning: 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.

1 curtida