Ошибки отправки

Отправка сообщений в STOMP.js опирается на корректную работу нескольких уровней: WebSocket-соединения, STOMP-фрейма, брокера сообщений и клиентской реализации очередей. Ошибка на любом из этих уровней приводит к сбоям доставки, которые часто проявляются не сразу, а в виде отсутствия реакции сервера или разрыва соединения.

Разрыв или нестабильность WebSocket-соединения

Наиболее частая причина ошибок отправки связана с состоянием WebSocket. STOMP.js использует WebSocket как транспорт, и любые сбои на этом уровне делают отправку невозможной.

Типичные сценарии:

  • соединение закрыто до вызова send
  • WebSocket находится в состоянии CONNECTING
  • произошёл незаметный разрыв соединения (silent disconnect)
  • прокси или балансировщик завершил соединение по таймауту

При попытке отправки в таком состоянии библиотека либо выбрасывает ошибку, либо «молча» игнорирует вызов, в зависимости от реализации клиента.

Критически важно учитывать состояние клиента перед отправкой:

  • client.connected === true
  • отсутствие события onWebSocketClose
  • завершённый connect handshake

Игнорирование этих условий приводит к потере сообщений без явного исключения.

Ошибки STOMP-фрейма SEND

STOMP-протокол строго регламентирует структуру отправляемого сообщения. Любое отклонение приводит к отказу брокера принять сообщение.

Классический фрейм отправки:

SEND
destination:/queue/test
content-type:application/json

{"data":123}

Ошибки возникают при:

  • отсутствии обязательного заголовка destination
  • некорректном формате destination (например, без /queue/ или /topic/)
  • передаче бинарных данных без указания content-type
  • нарушении структуры разделителя между заголовками и телом

Некоторые брокеры (RabbitMQ, ActiveMQ, Artemis) реагируют по-разному: одни закрывают соединение, другие отправляют ERROR-фрейм.

Ошибки сериализации payload

STOMP.js не выполняет глубокую проверку данных. Любая передача payload уходит «как есть» после сериализации.

Проблемные случаи:

  • передача объекта без JSON.stringify
  • циклические ссылки в объекте
  • некорректная кодировка строк
  • использование undefined или функций внутри payload

Пример проблемной отправки:

client.publish({
  destination: "/queue/test",
  body: { message: "test" }
});

В зависимости от версии STOMP.js это может привести к:

  • отправке строки "[object Object]"
  • выбросу ошибки сериализации
  • игнорированию сообщения

Корректный вариант:

client.publish({
  destination: "/queue/test",
  body: JSON.stringify({ message: "test" })
});

Ошибки заголовков (headers)

STOMP допускает передачу пользовательских заголовков, но брокеры часто накладывают ограничения.

Проблемные ситуации:

  • использование зарезервированных заголовков (content-length, subscription)
  • превышение допустимого размера заголовков
  • некорректные символы (не-ASCII без encoding)
  • дублирование ключей

Некоторые брокеры автоматически вычисляют content-length. Если клиент отправляет его вручную и значение не совпадает с фактическим телом, сообщение может быть отклонено или обрезано.

Перегрузка канала отправки

STOMP.js работает асинхронно, но не всегда учитывает backpressure на уровне брокера.

При высокой частоте вызовов send или publish возникают:

  • переполнение внутреннего буфера WebSocket
  • задержки отправки кадров
  • блокировка event loop из-за сериализации больших payload
  • потеря сообщений при разрыве соединения во время flush

Особенно часто это проявляется при циклической отправке:

setInterval(() => {
  client.publish({
    destination: "/queue/load",
    body: JSON.stringify(largePayload)
  });
}, 10);

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

Ошибки маршрутизации destination

destination является ключевым элементом маршрутизации сообщения. Ошибки в его формировании приводят к тому, что сообщение формально отправлено, но не доставлено ни одному подписчику.

Типичные ошибки:

  • перепутан префикс /queue и /topic
  • отсутствие ведущего слеша
  • использование несуществующего канала
  • динамически сформированный путь с ошибкой

Например:

destination: "queue/test"   // некорректно
destination: "/queue//test" // некорректно

Брокер может принять сообщение, но оно будет потеряно в routing layer.

Ошибки при отсутствии подтверждения доставки

STOMP по умолчанию не гарантирует delivery acknowledgment на уровне отправки. Это приводит к ситуации, когда клиент считает сообщение отправленным, но сервер его не обработал.

Проблемы усиливаются при:

  • использовании auto ack режима
  • отсутствии серверных ошибок ERROR frame
  • отключённой корреляции сообщений

Для диагностики необходимо использовать:

  • server-side logging
  • correlation-id в headers
  • transaction mode (BEGIN/COMMIT)

Ошибки транзакционной отправки

STOMP поддерживает транзакции, но STOMP.js реализует их ограниченно. Ошибки возникают при:

  • вызове commit без begin
  • отправке сообщений вне транзакции при ожидании commit
  • прерывании соединения до завершения транзакции

Пример некорректного сценария:

client.begin("tx1");

client.publish({
  destination: "/queue/test",
  body: "data",
  transaction: "tx1"
});

client.commit("tx1");

Если commit не доходит до брокера, все сообщения транзакции отбрасываются.

Ошибки обработки ERROR-фреймов

Брокер может вернуть STOMP ERROR frame, но STOMP.js не всегда обрабатывает его как исключение.

Причины появления ERROR:

  • неверные заголовки
  • отказ маршрутизации
  • нарушение прав доступа
  • превышение лимитов брокера

Пример фрейма:

ERROR
message:malformed frame
content-type:text/plain

Invalid destination

Если клиент не подписан на обработку ошибок, они теряются, и разработчик не видит причины сбоя отправки.

Ошибки повторной отправки (reconnect send race condition)

При автоматическом переподключении возможна ситуация, когда отправка происходит в момент восстановления соединения.

Сценарий:

  • WebSocket разрывается
  • STOMP.js инициирует reconnect
  • приложение вызывает send до завершения CONNECT
  • сообщение теряется

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

Несовместимость версий брокера и клиента

Некоторые ошибки отправки связаны не с кодом, а с различиями реализации STOMP:

  • STOMP 1.0 vs 1.1 vs 1.2
  • различия в экранировании заголовков
  • поддержка heart-beat параметров
  • ограничения на размер frame

Например, брокер может требовать STOMP 1.2, а клиент отправляет 1.0, из-за чего отправка проходит частично или блокируется.

Ошибки heartbeat при отправке

Heartbeat используется для поддержания соединения. При его неправильной настройке возможны побочные эффекты:

  • отправка во время heartbeat timeout
  • закрытие соединения в момент publish
  • ложное определение dead connection

Если heartbeat интервал слишком агрессивный, соединение может закрываться прямо во время отправки кадра.

Проблемы буферизации WebSocket

WebSocket имеет внутренний буфер отправки. При переполнении:

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

STOMP.js не всегда отслеживает состояние bufferedAmount, что приводит к «тихим» потерям сообщений при высокой нагрузке.

Ошибки из-за middleware брокера

В реальных системах между клиентом и брокером часто присутствуют промежуточные компоненты:

  • API gateway
  • STOMP proxy
  • security filter
  • message transformer

Они могут:

  • изменять destination
  • удалять заголовки
  • блокировать payload
  • возвращать некорректный ERROR frame

Для STOMP.js такие сбои выглядят как обычный network failure.

Неправильная обработка async send

Отправка в STOMP.js не гарантирует моментальную доставку. Ошибки возникают, когда логика приложения предполагает синхронный результат:

client.publish({...});
updateUI(); // предполагается, что сообщение уже доставлено

Фактически отправка может быть отложена WebSocket слоем, и при разрыве соединения сообщение не уйдёт вовсе.


Ошибки отправки в STOMP.js почти всегда являются результатом комбинации факторов: состояния соединения, структуры STOMP-фрейма, поведения брокера и сетевой нестабильности.