Heartbeat в STOMP — это встроенный механизм контроля «живости» соединения между клиентом и брокером сообщений, который позволяет обнаруживать разрывы канала связи, зависшие соединения и сетевые проблемы без ожидания таймаута TCP или явного разрыва WebSocket.
В контексте STOMP.js heartbeat реализуется поверх WebSocket-соединения и работает на уровне периодической отправки специальных контрольных байтов в обе стороны: от клиента к серверу и от сервера к клиенту. Эти сигналы не несут прикладной нагрузки и используются исключительно для диагностики состояния соединения.
Heartbeat в STOMP задаётся двумя параметрами:
Оба значения выражаются в миллисекундах.
Пример переговоров параметров heartbeat происходит во время CONNECT:
heart-beat: cx, sx
Где клиент предлагает свои значения, а брокер отвечает своими.
В STOMP протоколе heartbeat согласуется через заголовок:
heart-beat: <cx>,<cy>
Пример:
heart-beat: 10000,10000
Это означает:
После установления WebSocket-соединения STOMP-сессия переходит в фазу CONNECT/CONNECTED.
Далее:
Клиент отправляет CONNECT с параметром heart-beat
Сервер отвечает CONNECTED с собственными параметрами heart-beat
Стороны вычисляют фактические интервалы
Запускаются два независимых таймера:
Heartbeat в STOMP представляет собой одиночный символ:
\n
или байт 0x0A.
STOMP.js использует стандартный алгоритм:
Фактические интервалы вычисляются как:
Где:
Таким образом система гарантирует, что более «медленная» сторона определяет частоту, избегая перегрузки.
В библиотеке @stomp/stompjs heartbeat настраивается через объект подключения:
const client = new Client({
brokerURL: "ws://localhost:8080/ws",
heartbeatIncoming: 10000,
heartbeatOutgoing: 10000
});
Определяет, как часто клиент отправляет контрольные кадры в сторону сервера.
Определяет, как часто клиент ожидает heartbeat от сервера.
После подключения STOMP.js запускает два независимых механизма:
Отвечает за отправку heartbeat:
\nУпрощённая логика:
if (heartbeatOutgoing > 0) {
setInterval(() => {
ws.send("\n");
}, heartbeatOutgoing);
}
Отслеживает входящие сообщения:
Упрощённая модель:
setInterval(() => {
if (Date.now() - lastReceived > heartbeatIncoming) {
disconnect();
}
}, heartbeatIncoming);
Если одна из сторон перестаёт получать heartbeat:
onWebSocketClose или
onStompErrorWebSocket сам по себе не гарантирует:
Heartbeat компенсирует этот недостаток:
| Механизм | Функция |
|---|---|
| WebSocket ping/pong | низкоуровневая проверка канала |
| STOMP heartbeat | прикладной контроль доставки |
| TCP keepalive | системный уровень ОС |
STOMP heartbeat работает выше TCP и WebSocket, что делает его независимым от платформенных особенностей.
Брокеры сообщений (например, RabbitMQ, ActiveMQ, Spring WebSocket STOMP) также реализуют heartbeat:
\n клиентуПример поведения сервера:
heartbeatOutgoing: 10000
heartbeatIncoming: 10000
heartbeatOutgoing: 5000
heartbeatIncoming: 15000
Здесь приоритет отдаётся более частой отправке и более терпимому ожиданию.
heartbeatOutgoing: 0
heartbeatIncoming: 0
Используется редко, обычно в тестах или при внешнем контроле соединения.
Слишком агрессивный heartbeatIncoming может привести к:
Очень малые интервалы heartbeatOutgoing:
Если сервер не поддерживает heartbeat:
При включённой автоматической реконнекции heartbeat интегрирован в цикл восстановления:
Важно, что старые heartbeat-таймеры полностью уничтожаются при disconnect, иначе возможны утечки и дублирование отправок.
Heartbeat не измеряет задержку напрямую, но косвенно зависит от:
Если latency приближается к heartbeatIncoming, возможны ложные срабатывания таймаута. Поэтому интервал должен быть существенно больше среднего RTT.
Для стабильной работы в распределённых системах часто используется правило:
Это позволяет балансировать между скоростью обнаружения и устойчивостью к задержкам.
Heartbeat в STOMP.js формирует непрерывный цикл контроля соединения:
Этот механизм обеспечивает предсказуемое поведение поверх WebSocket и делает STOMP пригодным для систем реального времени, где критично быстрое обнаружение разрыва канала связи.