SSE приходит пачкой: где задерживается поток событий
Если SSE-события приходят пачкой, найдите первый участок, на котором отдельные события превращаются в накопленный ответ. Проверьте формат event-stream, выдачу данных приложением и буферизацию каждого посредника. Отключение буферизации nginx помогает только тогда, когда накопление происходит именно там; оно не исправляет задержку до прокси.
Что пользователь называет задержкой потока
В интерфейсе может долго ничего не меняться, а затем появиться несколько обновлений сразу. Причина находится не обязательно в сервере: приложение могло поздно сформировать события, промежуточный узел — накопить байты, а обработчик страницы — отложить отображение.
Начните с одного безопасного диагностического потока в своей среде. Дайте событиям последовательные номера и отмечайте этап наблюдения. Не подставляйте для проверки данные пользователей: для поиска границы задержки достаточно вымышленного состояния.
Разделите создание события, передачу из приложения, поступление байтов к следующему участнику и вызов браузерного обработчика. Запись «событие создано» в журнале ещё не доказывает, что оно уже покинуло приложение.
Сначала убедитесь, что браузеру передано целое событие
В описании SSE на MDN указан тип ответа text/event-stream и текстовая кодировка UTF-8. Сообщения разделяются пустой строкой. Если граница события не завершена, ожидание обработчика нельзя автоматически считать буферизацией прокси.
Также проверьте, какой обработчик должен принять сообщение. Именованное событие обрабатывается по своему имени; обычный onmessage предназначен для события без указанного имени. Полученные байты и обновившийся видимый список — разные наблюдения.
Для приёмки запишите ожидаемую структуру одного безобидного сообщения и способ его отображения. Затем отделите её от работы реального источника данных. Иначе редкое обновление источника легко принять за поломку канала доставки.
Карта мест, где может накопиться ответ
Таблица предлагает направления проверки по наблюдениям условного потока. Она не утверждает, что перечисленные узлы есть в каждом проекте. Сначала нарисуйте фактическую цепочку: приложение, используемые прокси, внешняя доставка и браузер.
| Наблюдение | Что ещё проверить | Подозреваемая граница | Какой вывод пока рано делать |
|---|---|---|---|
| События создаются поздно | График работы источника | До формирования ответа | Что виноват nginx |
| Созданы отдельно, выдаются вместе | Буферы среды и фактическую выдачу | Выход приложения | Что заголовок прокси заставит приложение отправить данные |
| До nginx поток отдельный, после накоплен | Конфигурацию нужного маршрута | Проксирование ответа | Что настройки соседнего location применяются здесь |
| После nginx поток есть, снаружи задержка | Правила следующего посредника | Внешний узел доставки | Что один заголовок управляет любой CDN |
| Байты приходят, обработчик молчит | Разделитель и имя события | Разбор в EventSource | Что сеть не передаёт данные |
| Обработчик срабатывает, экран ждёт | Очередь и обновление интерфейса | Клиентское отображение | Что нужна новая настройка сервера |
Что именно меняет proxy_buffering
В документации nginx proxy_buffering управляет буферизацией ответов проксируемого сервера. При выключенном режиме данные передаются клиенту по мере получения. Это настройка ответа, её не следует путать с буферизацией входящего запроса.
Там же описан заголовок ответа X-Accel-Buffering со значением no. Его влияние можно отключить через proxy_ignore_headers. Поэтому наличие заголовка в приложении не доказывает, что эффективная конфигурация nginx его учитывает.
Мы советуем выбирать минимальную область изменения для подтверждённого SSE-маршрута. Не выключайте буферизацию всего сайта только из-за одного потока. Перед применением проверьте, какие ещё ответы обслуживаются этим правилом и как будет оцениваться результат.
Если в цепочке есть другой посредник, отдельно изучите его поддержку потоковой доставки. Настройка nginx не обязывает внешний сервис передавать события немедленно. Сохраните наблюдение до и после каждого доступного участка, не раскрывая служебные адреса в публичном отчёте.
Выдача из приложения: строка в коде ещё не измерение
Разработчику нужно проверить не только создание текста сообщения, но и доступность этого текста на выходе используемой среды. Способ управления выдачей зависит от серверного стека. Название одной функции не является универсальным исправлением всех слоёв.
Сравнивайте одну и ту же последовательность событий на соседних границах. Если после приложения данные уже накоплены, менять внешнюю доставку преждевременно. Если задержка появляется позже, сохраните это различие как основание следующего изменения.
Для поддержки сервера полезна карта потока с точками наблюдения. В доработке приложения нужна отдельная задача, если выяснилось, что события поздно формируются или передаются из самой среды.
Поток ожил: проверьте ещё разрыв и возврат
MDN описывает автоматическую попытку EventSource восстановить закрытое соединение и возможность завершить его методом close. Успешное повторное соединение не доказывает, что бизнес-события за время паузы восстановлены. Это должен поддерживать серверный договор потока.
Определите, служит ли поток уведомлением об изменении или единственным источником данных. В первом случае после возврата может быть нужен запрос актуального состояния. Во втором требуется явно предусмотренный способ учесть пропущенное; нельзя молча считать всё полученным.
Проверьте и отсутствие повторного применения одного события в интерфейсе, если выбранный способ восстановления допускает повторную доставку. Порядок, идентификаторы и правила обновления задаются приложением. Транспорт сам по себе не определяет, как пересчитать список заказов.
План исправления с проверяемым результатом
- Зафиксируйте последовательность безобидных событий и ожидаемые обработчики.
- Проверьте тип ответа, кодировку и завершённую границу каждого события.
- Найдите первую доступную точку, где появляется накопление.
- Изучите конфигурацию этого слоя, включая возможное игнорирование заголовков.
- Измените одну подтверждённую причину в ограниченной тестовой среде.
- Сравните поступление событий до изменения и после него.
- Проверьте разрыв, восстановление состояния и штатное завершение подписки.
Результат приёмки — события доходят в согласованном режиме, а после разрыва состояние остаётся объяснимым. Не обещайте нулевую задержку: у источника, сети и клиента есть собственная работа. Для разработки веб-приложения лучше зафиксировать наблюдаемое требование, чем абстрактную просьбу сделать всё мгновенным.
Вопросы и ответы
Почему nginx отдаёт SSE-события пачкой?
Возможная причина — буферизация ответа, но сначала найдите участок накопления. Если приложение выдаёт события вместе, настройка nginx не сделает их ранними.
Какой формат нужен для EventSource?
Проверьте ответ text/event-stream, UTF-8 и разделение событий пустой строкой. Если событие именовано, клиент должен слушать соответствующее имя.
EventSource переподключился: все события восстановлены?
Нет, повторное соединение само по себе не подтверждает полноту данных. Предусмотрите получение актуального состояния либо поддерживаемый сервером способ восстановления.