Таймауты в STOMP.js формируются на нескольких уровнях одновременно: уровень WebSocket-соединения, уровень STOMP-протокола и уровень прикладной логики повторных подключений. Отсутствие централизованного механизма таймаута в библиотеке приводит к тому, что контроль времени ожидания распределяется между настройками транспорта и параметрами клиента STOMP.
Процесс установления соединения начинается с создания
WebSocket-инстанса. На этом уровне таймаут зависит не от STOMP.js, а от
реализации WebSocket в браузере или Node.js-окружении. В классическом
браузерном API отсутствует явный параметр connectTimeout, поэтому
задержка подключения выражается через косвенные механизмы: события
onerror, onclose и отсутствие
onopen в заданный интервал времени.
В STOMP.js подключение инициируется через объект клиента:
import { Client } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'wss://example.com/ws',
connectHeaders: {
login: 'user',
passcode: 'password'
},
debug: (msg) => console.log(msg)
});
client.activate();
Отсутствие явного подключения в течение заданного времени требует
внешнего контроля. Обычно используется обёртка с
Promise.race, где параллельно запускается таймер:
function connectWithTimeout(client, timeoutMs) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
client.deactivate();
reject(new Error('Connection timeout'));
}, timeoutMs);
client.onConn ect = () => {
clearTimeout(timer);
resolve();
};
client.onStompEr ror = () => {
clearTimeout(timer);
reject(new Error('STOMP error during connection'));
};
client.activate();
});
}
Такой подход компенсирует отсутствие встроенного механизма ограничения времени подключения.
WebSocket соединение не предоставляет прямого управления временем ожидания handshake на уровне API. Однако сетевой стек браузера и TCP-соединение могут зависать на стадии DNS-резолвинга, TLS-handshake или ожидания ответа сервера.
На практике таймаут транспортного уровня проявляется через отсутствие
событий open или close. Для серверных
реализаций Node.js с использованием ws возможно частичное
управление:
const WebSocket = require('ws');
const ws = new WebSocket('wss://example.com/ws', {
handshakeTimeout: 5000
});
Параметр handshakeTimeout ограничивает время установки
соединения до завершения HTTP Upgrade. STOMP.js при этом не участвует в
управлении данным уровнем, но его поведение зависит от результата
WebSocket-соединения.
STOMP-протокол определяет механизм heartbeat для обнаружения «зависших» соединений. Heartbeat представляет собой периодическую отправку пустых кадров, позволяющих определить активность канала.
В STOMP.js heartbeat задаётся в конфигурации клиента:
const client = new Client({
brokerURL: 'wss://example.com/ws',
heartbeatIncoming: 10000,
heartbeatOutgoing: 10000
});
Значения задаются в миллисекундах. heartbeatOutgoing
определяет интервал отправки сигналов клиентом, а
heartbeatIncoming — допустимый интервал ожидания сигналов
от брокера.
Отсутствие heartbeat в течение заданного времени приводит к закрытию соединения. Внутренне STOMP.js инициирует разрыв WebSocket-сессии, что позволяет трактовать ситуацию как таймаут неактивного соединения.
Критическим аспектом является согласование heartbeat между клиентом и брокером. Несоответствие значений приводит к ложным разрывам соединения, особенно при высокой сетевой задержке или нагрузке на сервер.
Хотя STOMP.js не вводит явного таймаута на уровне подписки, задержки доставки сообщений могут интерпретироваться как логические таймауты в прикладной системе.
Подписка создаётся через:
const subscription = client.subscribe('/topic/messages', (message) => {
console.log(message.body);
});
Отсутствие сообщений в течение определённого времени не приводит к автоматическому разрыву подписки. Таймаут реализуется внешней логикой, например через таймер ожидания первого сообщения:
let received = false;
const timer = setTimeout(() => {
if (!received) {
subscription.unsubscribe();
}
}, 15000);
client.subscribe('/topic/messages', (message) => {
received = true;
clearTimeout(timer);
});
Такой подход применяется для контроля «зависших» подписок, когда сервер не публикует данные.
STOMP.js включает встроенную поддержку повторного подключения через
параметр reconnectDelay. Этот параметр определяет задержку
между попытками восстановления соединения, но не ограничивает общее
время восстановления.
const client = new Client({
brokerURL: 'wss://example.com/ws',
reconnectDelay: 5000
});
Поведение при потере соединения включает цикл:
reconnectDelayactivate()Отсутствие лимита на количество попыток означает, что таймаут восстановления должен задаваться дополнительно:
let attempts = 0;
const maxAttempts = 5;
client.onWebSocketCl ose = () => {
if (attempts++ >= maxAttempts) {
client.deactivate();
}
};
Таким образом формируется прикладной таймаут восстановления соединения, не предусмотренный напрямую библиотекой.
STOMP-клиент обрабатывает входящие кадры асинхронно. При высокой нагрузке возможны задержки обработки, которые не интерпретируются как ошибки протокола.
Проблема возникает при блокировке event loop, когда входящие сообщения продолжают поступать, но обработчик не выполняется своевременно. В таких случаях применяется внешнее измерение latency:
const start = Date.now();
client.subscribe('/topic/ping', (msg) => {
const latency = Date.now() - start;
console.log('Latency:', latency);
});
Если задержка превышает допустимый порог, соединение может быть принудительно пересоздано, что фактически реализует прикладной таймаут обработки сообщений.
Поведение STOMP.js при таймаутах определяется наложением нескольких независимых механизмов:
Конфликты между уровнями возникают при несогласованных значениях. Например, слишком агрессивный heartbeat может разрывать соединение при нормальной сетевой задержке, а слишком редкий heartbeat приводит к позднему обнаружению обрыва канала.
Особое значение имеет синхронизация heartbeat с параметрами брокера, такими как ActiveMQ, RabbitMQ STOMP plugin или SockJS-серверы. Несовпадение интервалов приводит к эффекту «плавающих разрывов», когда соединение нестабильно без явных ошибок.
В браузере контроль таймаутов ограничен отсутствием низкоуровневого доступа к TCP-соединению. Все механизмы реализуются через события WebSocket API и таймеры JavaScript.
В Node.js появляется дополнительная гибкость через библиотеку
ws, где доступны параметры handshakeTimeout,
maxPayload, а также возможность перехвата сокетного
уровня.
Это различие приводит к необходимости унификации логики таймаутов на уровне STOMP-клиента, независимо от окружения выполнения.
При длительной деградации сети таймауты проявляются каскадно:
Такая цепочка требует согласованного управления таймерами, иначе возможно одновременное срабатывание нескольких механизмов восстановления, что приводит к шторму переподключений и избыточной нагрузке на брокер.