При релизе HTTP/2-соединение может получить GOAWAY — служебный кадр о его завершении. Сам по себе он не доказывает сбой: проверять нужно, дочитал ли клиент активные ответы и смог ли продолжить работу через новое соединение.
Для проверки graceful shutdown, то есть плавного завершения работы, воспроизведите выкладку с уже начатым долгим запросом и параллельными новыми запросами. Успешная загрузка главной после релиза этого не подтверждает.
Что означает GOAWAY и NO_ERROR
По RFC 9113, раздел 6.8, GOAWAY позволяет прекратить приём новых потоков, завершив ранее начатые. Код NO_ERROR совместим с плановым завершением, но не гарантирует доставку всех ответов.
Поле Last-Stream-ID — верхняя граница потоков, которые отправитель мог обработать, а не номер последнего успешного ответа. Потоки выше этой границы можно повторить на новом соединении; для оборванной операции ниже или на границе результат может остаться неизвестным. При нескольких GOAWAY учитывают последнюю полученную границу.
Если ошибка возникает и вне выкладки, начните с общей диагностики ERR_HTTP2_PROTOCOL_ERROR. Здесь задача уже: проверить переход между старым и новым обслуживающим процессом.
1. Определите, кто завершает соединение
Нарисуйте путь: клиент → CDN или балансировщик → nginx → приложение. Укажите протокол каждого участка и компонент, который обновляется.
HTTP/2 в браузере описывает соединение до ближайшего узла. Если его завершает CDN, наблюдаемый GOAWAY нельзя автоматически приписывать nginx на origin. Сопоставьте время события с журналом нужного узла, версией приложения и идентификатором запроса.
2. Подготовьте проверку без реальных заказов
На стенде с той же схемой прокси выберите безопасный GET, ответ которого длится достаточно долго, чтобы пересечь момент выкладки. Подойдёт контролируемая тестовая выгрузка с заранее известным содержимым.
До теста зафиксируйте:
- ожидаемые статус, содержимое и полный размер несжатого тестового ответа;
- способ связать запрос с логами и обслуживающим узлом;
- фактический HTTP/2 и переиспользование соединения клиентом;
- время начала вывода узла из обслуживания и крайний срок остановки.
Не используйте настоящую оплату или создание заявки для проверки обрыва. Если нужны операции записи, изолируйте их в тестовом контуре.
3. Пересеките запросом момент релиза
- Запустите долгий GET и подтвердите, что сервер начал его обрабатывать.
- Тем же HTTP/2-клиентом отправляйте короткие безопасные запросы через переиспользуемое соединение. Записывайте их результат до, во время и после выкладки.
- Выполните штатный сценарий релиза на стенде: вывод узла из балансировки и остановку либо reload — именно то, что делает ваш deploy.
- Проверьте полное тело долгого ответа, завершение потока и отсутствие транспортной ошибки. Одних заголовков со статусом 200 недостаточно.
- Подтвердите, что дальнейшие запросы обслуживает новое соединение и нужная версия. Отдельно проверьте подключение нового клиента.
Используйте HTTP/2-клиент с трассировкой кадров: сохраните код GOAWAY, Last-Stream-ID, номера затронутых потоков и время закрытия. Новый процесс curl на каждый запрос не воспроизводит поведение долгоживущего соединения.
Отдельно считайте сетевые попытки и итоговые ответы. Прозрачный повтор клиента способен скрыть обрыв первой попытки; без трассировки тест покажет лишь итоговый успех.
4. Сверьте завершение nginx и приложения
У nginx reload запускает новые worker-процессы и просит старые завершиться плавно. QUIT означает плавную остановку, TERM и INT — быструю; это разные сценарии, описанные в документации управления nginx.
Проверьте, какой сигнал реально отправляет deploy или менеджер контейнеров. Если nginx дождался клиента, но приложение остановили раньше, динамический ответ всё равно может оборваться.
Директива worker_shutdown_timeout ограничивает ожидание завершения worker: по истечении срока nginx пытается закрыть оставшиеся соединения. Сравните этот срок с временем долгих запросов, ожиданием балансировщика и предельным временем жизни контейнера.
Не увеличивайте все таймауты наугад. Найдите слой, который первым закрыл соединение, и проверьте, достаточно ли предусмотренного окна для ваших конечных запросов. Для бесконечных SSE-потоков нужен отдельный сценарий переподключения.
Как оценить результат
- GOAWAY с NO_ERROR, ответы полные, новые запросы проходят. Есть признаки штатного перехода; сам кадр не повод считать сайт упавшим.
- Долгий ответ обрывается у границы остановки. Сопоставьте событие с таймаутом worker, остановкой приложения и принудительным завершением контейнера.
- Старые запросы заканчиваются, новые не проходят. Проверьте готовность новой версии и момент возврата узла в балансировку.
- Ответ на POST потерян. Сначала сверяйте результат операции; правила безопасного повтора API защищают от повторного создания сущности.
В протоколе проверки сохраните версию, маршрут, времена, исход каждой попытки и подтверждение полного ответа. Удалите из трассировок токены, Cookie и персональные данные.
Следующий шаг
Регулярная проверка публичного URL в Web-Puls дополняет приёмку релиза, но не доказывает корректность завершения активных HTTP/2-потоков: для этого нужен описанный тест.
Если обрывы воспроизводятся, а граница сбоя неясна, отправьте заявку на профессиональную поддержку: укажите публичный URL, время с часовым поясом, схему прокси, способ выкладки и очищенные фрагменты трассировки. Специалист оценит симптомы и предложит формат дальнейшего разбора.