Что такое heartbeat — и почему «открытое» соединение может быть давно мёртвым

Ты сделал чат на WebSocket. Всё летает. Потом тестировщица садится в метро, связь пропадает на минуту, она выходит — и чат молчит. Ни ошибки, ни «переподключаюсь». Сокет на её телефоне считает, что он всё ещё подключён.
Смотри, тут хитрая штука. Когда связь рвётся без прощания — телефон уехал в тоннель, ноутбук закрыли, — никто не присылает сигнал «я отключился». Обе стороны просто перестают слышать друг друга. И каждая думает, что собеседник молчит, потому что ему нечего сказать.
Встроенная в TCP проверка «ты жив?» в Linux по умолчанию включается только через два часа тишины. Для чата это вечность. Поэтому приложения проверяют связь сами. Это и есть heartbeat.
Что такое heartbeat
Heartbeat («сердцебиение») — это маленькое служебное сообщение, которое одна сторона регулярно шлёт другой, чтобы показать: «я жив, связь есть».
Как врач слушает пульс. Важен не сам удар, а то, что он приходит регулярно. Пропало несколько ударов подряд — пора тревожиться.
В самом сообщении обычно ничего нет. Ни данных, ни смысла. Его ценность — в факте прихода и во времени.
Как это работает
Схема почти всегда одна и та же.
- Клиент каждые N секунд шлёт «пинг».
- Сервер отвечает «понг».
- Каждая сторона запоминает, когда в последний раз что-то слышала.
- Если тишина длится дольше порога — соединение считается мёртвым. Его закрывают и переподключаются.
Порог берут с запасом: обычно 2–3 интервала. Один пропущенный пинг — это может быть просто медленная сеть. Три подряд — уже нет.
Проиграй ту поездку в метро по секундам. В 0 и в 25 пинги ушли, понги вернулись. На 30-й секунде поезд въехал в тоннель. Пинг на 50-й ушёл в никуда. Пинг на 75-й — тоже, и тишина уже дольше 75 секунд. Клиент закрывает сокет, показывает «Нет связи» и начинает переподключаться. Связь вернулась на 90-й — через пару секунд чат снова живой. Без heartbeat этот же телефон просидел бы с «онлайн» до двух часов.
Кто должен пинговать — клиент или сервер? Неважно, главное, чтобы обе стороны следили за тишиной. Сервер тоже хочет знать, что клиента нет: иначе он держит память под тысячи соединений-призраков и шлёт им сообщения впустую.
Вот как это выглядит у тебя в коде:
let lastSeen = Date.now();
socket.onmessage = () => { lastSeen = Date.now(); };
setInterval(() => {
if (Date.now() - lastSeen > 75_000) {
socket.close(); // тишина дольше трёх интервалов
reconnect();
} else {
socket.send(JSON.stringify({ type: "ping" }));
}
}, 25_000);
Где ты это уже встречал, даже не замечая:
- Supabase Realtime. Клиент по умолчанию шлёт heartbeat каждые 25 секунд, сервер отвечает. Интервал меняется опцией
heartbeatIntervalMsвcreateClient. - Socket.IO. Сервер пингует клиента сам, интервал и таймаут — в настройках
pingIntervalиpingTimeout.
Зачем это тебе
Heartbeat решает сразу две задачи — и обе бьют по новичкам.
Первая — поймать мёртвое соединение. Без пульса твой интерфейс показывает «онлайн», а сообщения уходят в пустоту. С пульсом ты через минуту знаешь правду и можешь показать «Нет связи, переподключаемся…».
Вторая — не дать соединению умереть. Между тобой и сервером стоят прокси и балансировщики. Они закрывают соединения, по которым долго ничего не идёт. У nginx, например, proxy_read_timeout по умолчанию 60 секунд. Чат, где минуту никто не пишет, отвалится сам. Пинг каждые 25 секунд держит канал «тёплым».
Та же идея живёт и вне сокетов. Фоновый воркер раз в минуту пишет в таблицу «я жив». Cron-задача проверяет, не застыла ли эта отметка. Если застыла — тебе приходит алерт, а не жалоба пользователя.
И ещё одна деталь, которую забывают. Поймал обрыв — не переподключайся мгновенно и в цикле. Если сервер упал, тысяча клиентов, долбящих его каждые 100 миллисекунд, не дадут ему подняться. Подожди 1 секунду, потом 2, потом 4 — и добавь немного случайности к паузе.
Как часто слать heartbeat?
Обычно раз в 20–30 секунд — чуть чаще, чем самый короткий таймаут прокси на пути. Чаще не нужно: на мобильном каждый пинг будит радиомодуль и тратит батарею.
Heartbeat и health-check — одно и то же?
Похоже, но нет. Health-check — это когда кто-то снаружи спрашивает сервис «ты здоров?». Heartbeat — когда сервис сам регулярно сообщает «я жив».
Что делать, если вкладка ушла в фон?
Браузеры притормаживают таймеры в фоновых вкладках, и пинги могут опаздывать. Поэтому при возвращении на вкладку стоит сразу проверить связь, а не ждать следующего тика.
Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.





