«client prematurely closed connection», хотя пользователь никуда не уходил

badcasedaily1 5 минут назад Краткое содержание статьи «client prematurely closed connection», хотя пользователь никуда не уходил Средний 11 мин 14 Блог компании OTUS Nginx * Системное администрирование * Серверное...
Will Anthropic have the best AI model at the end of October 2026?
Значимый прорыв формирует отрасль ИИ: badcasedaily1 5 минут назад Краткое содержание статьи «client prematurely closed connection», хотя пользователь никуда не уходил Средний 11 мин 14 Блог компании OTUS Nginx * Системное администрирование * Серверное администрирование * DevOps * Кейс Привет, Хабр! Строку client prematurely closed connection в error. log nginx видел каждый, кто хоть раз поднимал уровень логов до info, а в access.
log напротив того же запроса стоит 499. Читают её обычно буквально, как «клиент ушёл сам». Пользователь закрыл вкладку, мобильный интернет моргнул, к серверу претензий нет.
Технические детали
Алерт на 5 xx молчит, 499 в него не входит, и про этот код вспоминают, только когда таких строк набираются тысячи в час. Кода 499 нет ни в одном RFC. Его придумали в nginx.
Нужен он был, чтобы было что записать в лог, когда отвечать уже некому. Иногда пользователь действительно ушёл с сайта. Иногда «пользователем» оказывается балансировщик, который устал ждать и уже отдал клиенту 504, а бэкенд в это время спокойно дорабатывает запрос, результат которого никто не увидит.
Такие ситуации особенно важно учитывать при проектировании инфраструктуры высоконагруженных систем, где таймауты, повторные запросы и лишняя работа бэкенда могут заметно влиять на производительность. А с 24 марта 2026 года, когда в nginx 1. 7 keepalive к апстримам включили по умолчанию, каждый такой обрыв ещё и выбивает соединение из пула.
Отраслевые последствия
Код, который придумали для логаОпределение 499 находится в src/http/ngx_http_request. h, и комментарий над ним объясняет, зачем код понадобился:/* * HTTP does not define the code for the case when a client closed * the connection while we are processing its request so we introduce * own code to log such situation when a client has closed the connection * before we even try to send the HTTP header to it */ #define NGX_HTTP_CLIENT_CLOSED_REQUEST 499Граница записана в последних словах комментария: «before we even try to send the HTTP header». Клиенту 499 никогда не отправляется.
Он существует только в access log и записывается, если клиент ушёл раньше, чем nginx начал отдавать ответ. Обрывать запросы я пробовал на nginx 1. 4 разными способами, от таймаута curl и отмены в браузере до gRPC‑дедлайна и клиента, который пропал без единого пакета, а за nginx стояли бэкенды на Go и на aiohttp.
Проще всего 499 получить через curl --max-time 2 на ручку, которая отвечает 6 секунд, и в логе это выглядит так:st=499 rt=2. 002 us=- uht=- bbs=0 epoll_wait() reported that client prematurely closed connection, so upstream connection is closed too while sending request to upstream$upstream_status пустой, потому что бэкенд не успел ответить.
Этот прогресс даёт важные сигналы о будущем отрасли, и технологический мир внимательно наблюдает.



