Настройка heartbeat

Heartbeat в протоколе STOMP используется для контроля живости соединения между клиентом и брокером сообщений. В STOMP.js этот механизм реализуется на уровне периодической отправки управляющих кадров, позволяющих обнаруживать «зависшие» соединения, разрывы сети и неотвечающие серверы.

Heartbeat представляет собой два независимых интервала:

  • интервал отправки heartbeat от клиента к серверу
  • интервал ожидания heartbeat от сервера к клиенту

Оба значения задаются в миллисекундах и передаются в момент установления соединения.


Принцип работы heartbeat

После установления соединения клиент и сервер обмениваются параметрами heartbeat в рамках команды CONNECT и ответа CONNECTED.

Формат согласования выглядит следующим образом:

heart-beat: cx,cy

где:

  • cx — период отправки heartbeat клиентом
  • cy — период ожидания heartbeat от сервера

Если одна из сторон не поддерживает heartbeat, значение может быть 0.


Особенности реализации в STOMP.js

STOMP.js автоматически управляет heartbeat после подключения, если параметры заданы при инициализации клиента.

Основные особенности:

  • heartbeat отправляется только при активном соединении WebSocket
  • используется таймер JavaScript (setInterval / setTimeout)
  • отсутствие входящих heartbeat фиксируется как потеря соединения
  • heartbeat может быть отключён полностью

Настройка heartbeat при создании клиента

В STOMP.js heartbeat задаётся через параметры клиента:

import { Client } from '@stomp/stompjs';

const client = new Client({
  brokerURL: 'ws://localhost:15674/ws',

  heartbeatIncoming: 10000,
  heartbeatOutgoing: 10000,
});

Параметры:

heartbeatOutgoing

  • интервал отправки heartbeat от клиента
  • значение в миллисекундах
  • 0 отключает отправку

heartbeatIncoming

  • интервал ожидания heartbeat от сервера
  • значение в миллисекундах
  • 0 отключает проверку входящих heartbeat

Поведение при включённом heartbeat

При активных настройках:

heartbeatOutgoing: 10000,
heartbeatIncoming: 10000

STOMP.js выполняет следующие действия:

  • каждые 10 секунд отправляет управляющий кадр (обычно newline \n)
  • отслеживает входящие heartbeat от сервера
  • сбрасывает таймер соединения при получении любого кадра
  • инициирует разрыв соединения при превышении таймаута

Формат heartbeat в WebSocket

Heartbeat в STOMP не является отдельным сообщением протокола WebSocket. Вместо этого используются:

  • пустые кадры (\n)
  • служебные байты, поддерживаемые брокером

Пример отправки heartbeat:

\n

Это минимальный допустимый payload, который поддерживается большинством STOMP-брокеров.


Согласование heartbeat с сервером

При подключении клиент отправляет:

CONNECT
accept-version:1.2
heart-beat:10000,10000

Сервер отвечает:

CONNECTED
heart-beat:10000,10000

Фактические значения могут отличаться в зависимости от конфигурации брокера. Например, сервер может изменить интервалы на более агрессивные или отключить входящий heartbeat.


Обработка отсутствия heartbeat

Если входящие данные отсутствуют дольше, чем указано в heartbeatIncoming, STOMP.js инициирует разрыв соединения:

  • соединение переводится в состояние CLOSED
  • вызывается callback onWebSocketClose
  • клиент может автоматически попытаться переподключиться (если настроено)

Пример логики реакции:

const client = new Client({
  brokerURL: 'ws://localhost:15674/ws',

  heartbeatIncoming: 5000,
  heartbeatOutgoing: 5000,

  onDisconnect: () => {
    console.log('Соединение потеряно');
  },
});

Влияние heartbeat на стабильность соединения

Heartbeat напрямую влияет на:

  • обнаружение обрывов сети
  • работу через NAT и прокси
  • нагрузку на сервер
  • поведение reconnect-логики

Слишком маленькие значения приводят к:

  • ложным разрывам соединения
  • повышенной сетевой активности

Слишком большие значения приводят к:

  • позднему обнаружению обрывов
  • задержкам восстановления соединения

Рекомендованные значения

Практические диапазоны:

  • локальная разработка: 5000–10000 мс
  • продакшен-системы: 10000–30000 мс
  • нестабильные сети: 20000–60000 мс

Часто используется симметричная настройка:

heartbeatIncoming: 15000,
heartbeatOutgoing: 15000

Отключение heartbeat

Heartbeat можно полностью отключить:

const client = new Client({
  brokerURL: 'ws://localhost:15674/ws',

  heartbeatIncoming: 0,
  heartbeatOutgoing: 0,
});

В этом случае:

  • отсутствует контроль живости соединения на уровне STOMP
  • ответственность за reconnect полностью переходит к приложению или WebSocket-слою
  • некоторые брокеры могут закрывать соединение по таймауту

Heartbeat и переподключение

Heartbeat часто используется вместе с логикой автоматического reconnect:

const client = new Client({
  brokerURL: 'ws://localhost:15674/ws',

  reconnectDelay: 5000,
  heartbeatIncoming: 10000,
  heartbeatOutgoing: 10000,
});

Поведение:

  • heartbeat фиксирует потерю соединения быстрее TCP-таймаутов
  • reconnectDelay задаёт паузу перед повторным подключением
  • комбинация уменьшает вероятность «зависших» сессий

Тайминг и внутренняя логика STOMP.js

Внутри STOMP.js heartbeat реализован через таймеры:

  • outgoing heartbeat: периодический setInterval
  • incoming heartbeat: контроль времени последнего полученного кадра

Каждый входящий STOMP-фрейм обновляет таймер активности соединения. Даже SUBSCRIBE или MESSAGE считаются активностью и сбрасывают таймер.


Совместимость с брокерами

Поведение heartbeat зависит от брокера:

  • RabbitMQ STOMP plugin — поддерживает heartbeat и активно его использует
  • ActiveMQ — позволяет гибко настраивать интервалы
  • Spring WebSocket STOMP — требует согласованной настройки server-side heartbeat
  • брокеры без поддержки heartbeat игнорируют параметры

Частые ошибки при настройке

  1. Несогласованные интервалы клиента и сервера Приводит к немедленным разрывам соединения.

  2. Установка heartbeatIncoming без heartbeatOutgoing Может вызвать некорректную детекцию разрыва.

  3. Слишком агрессивные значения (например, 1000 мс) Перегружают сеть и брокер.

  4. Ожидание heartbeat при отключённой серверной поддержке Соединение будет считаться «мертвым» ошибочно.


Диагностика heartbeat

Для анализа поведения используются:

  • логирование STOMP.js (debug callback)
  • мониторинг WebSocket frames
  • серверные логи брокера
  • проверка интервалов CONNECTED/heart-beat

Пример включения отладки:

const client = new Client({
  brokerURL: 'ws://localhost:15674/ws',
  debug: (msg) => console.log(msg),
});

Поведение при сетевых сбоях

При кратковременных сбоях heartbeat:

  • фиксирует отсутствие входящих данных
  • инициирует закрытие соединения быстрее TCP timeout
  • позволяет быстрее восстановить подписки после reconnect

При длительных обрывах:

  • соединение закрывается принудительно
  • требуется полная переустановка session state

Влияние на производительность

Heartbeat создаёт минимальную нагрузку:

  • 1 байт каждые N секунд
  • один таймер на соединение

Однако при большом количестве соединений:

  • возрастает число таймеров
  • увеличивается нагрузка на event loop
  • повышается сетевой шум

Поэтому в высоконагруженных системах heartbeat настраивается с учётом масштаба соединений.