Как исправить ошибки /message-bus или долгого опроса в форуме Discourse

1. Проблема

При настройке Discourse с использованием CDN часто возникает следующая ошибка:

/message-bus/204234de907442e8b77e153786a58e5b/poll
Ошибка подключения / тайм-аут / аномальный код состояния

Последствия:

  • Сбои уведомлений: Красная точка (новое личное сообщение/ответ) больше не появляется в реальном времени; обновления могут приходить с задержкой или не приходить вовсе.

  • Нарушение обновлений в реальном времени: Новые сообщения, лайки и голоса не обновляются автоматически; требуется ручное обновление страницы.

  • Ухудшение пользовательского опыта: Появляются сообщения «Подключение потеряно»; взаимодействия работают с задержкой.

  • Увеличение нагрузки на сервер: Фронтенд продолжает повторные попытки опроса, создавая дополнительную нагрузку на исходный сервер.

Причина: Discourse использует механизм длинного опроса (long polling) для поддержания связи в реальном времени. Многие CDN по умолчанию включают кэширование, сокращают время ожидания, требуют проверки через капчу/брандмауэр или буферизуют длительные соединения, что приводит к прерываниям или возврату закэшированных ответов, нарушающих работу в реальном времени.


2. Общий подход (Приоритет стабильности)

  • Разделение доменов: Маршрутизация MessageBus через выделенный домен, который подключается напрямую к исходному серверу.

  • Слой обратного прокси (Nginx):

    • Включить CORS для /message-bus.

    • Отключить буферизацию прокси, увеличить таймауты, явно запретить кэширование.

  • Слой CDN (если всё ещё используется):

    • Настроить /message-bus/* с параметрами: без кэширования, увеличенный таймаут, отсутствие проверок JS/CAPTCHA/ограничения скорости, а также передача куки и заголовков авторизации.

    • Или полностью обойти CDN.


3. Шаги реализации

1) Настройка переменных окружения Discourse

Отредактируйте файл app.yml (обычно находится в /var/discourse/containers/app.yml) и добавьте/измените секцию env::

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

Примените изменения (официальное развёртывание):

cd /var/discourse
./launcher rebuild app

Пояснение:

  • DISCOURSE_LONG_POLLING_BASE_URL указывает фронтенду использовать домен MessageBus.

  • REDIS_ENABLED должен оставаться включённым.


2) DNS и сертификат

  • Настройте messagebus.example.com так, чтобы он указывал напрямую на исходный сервер, минуя CDN (лучшая практика).

  • Установите действительный HTTPS-сертификат для домена.


3) Обратный прокси (домен MessageBus) и CORS в Nginx

Добавьте или обновите следующие настройки в блоке server для messagebus.example.com:

location ^~ /message-bus {

    # (1) Обработка предварительного запроса 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) Обратный прокси к Discourse
    proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
    # или, если используется standalone:
    # proxy_pass http://127.0.0.1:3000;

    # (3) Предотвращение дублирования заголовков CORS
    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 для запросов
    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) Настройки стабильности для длинного опроса
    proxy_read_timeout    120s;
    proxy_send_timeout    120s;
    proxy_connect_timeout 60s;

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

    # (6) Явный запрет кэширования
    add_header Cache-Control "no-store, no-cache, must-revalidate" always;
}

:warning: Примечание по безопасности: Если используется Access-Control-Allow-Credentials: true, заголовок Origin не может быть *; он должен точно совпадать с доменом форума.


4) Правила CDN (если форум всё ещё находится за CDN)

Рекомендуется установить без кэширования + увеличенный таймаут + обход WAF/ограничения скорости для следующих путей:

Пример регулярного выражения:

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

Политика:

  • Отключение кэширования в браузере/узлах (no-store/no-cache).

  • Таймауты upstream/read/idle ≥ 60–120 с.

  • Отключение проверки JS/CAPTCHA/управления ботами.

  • Передача куки и заголовков авторизации (не удалять).


4. Как проверить успешность

1) Инструменты разработчика браузера → Сеть

На странице форума:

  • Отслеживайте запросы /message-bus/…/poll.

  • Запрос должен «висеть» около 20–60 секунд, затем возвращать 200 (возможно, пустой ответ).

  • Следующий запрос опроса запускается автоматически.

Проверьте заголовки ответа:

  • Access-Control-Allow-Origin: https://bbs.example.com

  • Cache-Control: no-store

  • Отсутствие заголовков Age, X-Cache: HIT или CF-Cache-Status: HIT (означает, что кэширование не применено).

Распространённые проблемы:

  • Ошибки с фиксированным интервалом 10с/30с → тайм-аут на границе или исходном сервере.

  • 504/524: тайм-аут.

  • 499: разрыв соединения на промежуточном уровне.

  • 403/401: блокировка WAF или авторизацией.


2) Быстрая проверка через командную строку (опционально)

Проверьте подключение и заголовки (не полный опрос):

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

Примечание: Фактические опросы требуют контекста сессии; данная команда проверяет только CORS и подключение.

2 лайка