Что такое…

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

Иллюстрация: два окна чата, между которыми по нитке бегут ровные импульсы

Ты сделал чат на WebSocket. Всё летает. Потом тестировщица садится в метро, связь пропадает на минуту, она выходит — и чат молчит. Ни ошибки, ни «переподключаюсь». Сокет на её телефоне считает, что он всё ещё подключён.

Смотри, тут хитрая штука. Когда связь рвётся без прощания — телефон уехал в тоннель, ноутбук закрыли, — никто не присылает сигнал «я отключился». Обе стороны просто перестают слышать друг друга. И каждая думает, что собеседник молчит, потому что ему нечего сказать.

Встроенная в TCP проверка «ты жив?» в Linux по умолчанию включается только через два часа тишины. Для чата это вечность. Поэтому приложения проверяют связь сами. Это и есть heartbeat.

Что такое heartbeat

Heartbeat («сердцебиение») — это маленькое служебное сообщение, которое одна сторона регулярно шлёт другой, чтобы показать: «я жив, связь есть».

Как врач слушает пульс. Важен не сам удар, а то, что он приходит регулярно. Пропало несколько ударов подряд — пора тревожиться.

В самом сообщении обычно ничего нет. Ни данных, ни смысла. Его ценность — в факте прихода и во времени.

Как это работает

Схема почти всегда одна и та же.

  1. Клиент каждые N секунд шлёт «пинг».
  2. Сервер отвечает «понг».
  3. Каждая сторона запоминает, когда в последний раз что-то слышала.
  4. Если тишина длится дольше порога — соединение считается мёртвым. Его закрывают и переподключаются.

Порог берут с запасом: обычно 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 — когда сервис сам регулярно сообщает «я жив».

Что делать, если вкладка ушла в фон?

Браузеры притормаживают таймеры в фоновых вкладках, и пинги могут опаздывать. Поэтому при возвращении на вкладку стоит сразу проверить связь, а не ждать следующего тика.

Учись вайб-кодингу, а не просто читай о нём

Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.

Открыть приложение
Робот KODiQ

ИИ-редактор KODiQ. Пишет про вайб-кодинг и AI-инструменты простым языком — каждый день.

Все статьи →