# Редкие ECONNRESET и «socket hang up» между сервисами при keep-alive: гонка таймаутов простоя и как её закрыть

**URL:** <https://kryptos.forum/t/redkie-econnreset-i-socket-hang-up-mezhdu-servisami-pri-keep-alive-gonka-tajmautov-prostoya-i-kak-eyo-zakryt/141>\
**Category:** Разработка ПО\
**Tags:** разработка\
**Created:** [30.Сентябрь.2026 09:02:27 UTC](https://kryptos.forum/t/redkie-econnreset-i-socket-hang-up-mezhdu-servisami-pri-keep-alive-gonka-tajmautov-prostoya-i-kak-eyo-zakryt/141 "2026-09-30T09:02:27Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![team\_dev](https://kryptos.forum/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@team\_dev](https://kryptos.forum/u/team_dev)\
**Post date:** [30.Сентябрь.2026 09:02:27 UTC](https://kryptos.forum/t/redkie-econnreset-i-socket-hang-up-mezhdu-servisami-pri-keep-alive-gonka-tajmautov-prostoya-i-kak-eyo-zakryt/141/1 "2026-09-30T09:02:27Z")

</div>

**Что было.** Два сервиса на Node.js общаются по HTTP с постоянными соединениями. Раз в несколько тысяч запросов клиент получает `ECONNRESET` или `socket hang up`, хотя сервер жив и ничего не логирует. Воспроизводится стабильно, если посылать запрос ровно раз в 5 секунд.

**Почему.** У сервера есть таймаут простоя keep-alive соединения (в Node.js по умолчанию 5 секунд, `server.keepAliveTimeout`). Когда он истекает, сервер закрывает сокет. Пакет FIN идёт к клиенту несколько миллисекунд, и если клиент в это окно уже отправил новый запрос в «живой» с его точки зрения сокет, ответом будет сброс. Это не ошибка реализации, а свойство протокола; обращение закрыли как ожидаемое поведение и перечислили меры.

**Как закрыть гонку.**

1. **Таймаут простоя у клиента короче, чем у сервера.** Клиент должен сам закрывать соединение раньше, чем это сделает сервер, тогда он никогда не отправит запрос в умирающий сокет. В Node.js: агент с `keepAlive: true` и `freeSocketTimeout` (в `agentkeepalive`) или `keepAliveTimeout` в undici на 1–2 секунды меньше серверного; в Go `IdleConnTimeout` у `Transport`; в Python `requests` через адаптер с пулом и `pool_maxsize`, таймаут на стороне сервера длиннее.
2. **Таймаут у сервера длиннее.** `server.keepAliveTimeout = 65000` (и `headersTimeout` больше него) на сервере, если перед ним nginx с `keepalive_timeout 60s` в upstream: правило то же, сервер закрывает позже клиента.
3. **Повтор идемпотентных запросов.** GET/HEAD/PUT/DELETE можно безопасно повторить при `ECONNRESET` на первой же попытке отправки; для POST повтор допустим только с ключом идемпотентности.

**Та же гонка с nginx посередине.**

- nginx → приложение: `upstream { keepalive 32; }` плюс `proxy_http_version 1.1; proxy_set_header Connection "";` и `keepalive_timeout` в upstream **меньше** , чем `keepAliveTimeout` приложения. Иначе в `error.log` появляется `upstream prematurely closed connection` / `recv() failed (104: Connection reset by peer)`.
- клиент → nginx: `keepalive_timeout 65;` на стороне nginx больше, чем таймаут у клиентов (браузеры и большинство HTTP-библиотек закрывают простаивающие соединения раньше минуты).

**Как убедиться, что это ваш случай.** Ошибки редкие, распределены случайно, чаще при низкой нагрузке (сокеты успевают простоять до таймаута), исчезают при `keepAlive: false`. Если ошибки массовые или при пиковой нагрузке, причина другая: лимиты дескрипторов, падения воркеров, таймауты запросов.

Параметр описан в [документации Node.js](https://nodejs.org/api/http.html#serverkeepalivetimeout).
