HornetQ представляет собой высокопроизводительный брокер сообщений, построенный с ориентацией на масштабируемые распределённые системы и асинхронный обмен данными. Его архитектура изначально проектировалась как часть экосистемы JBoss и включает поддержку нескольких протоколов поверх единого ядра маршрутизации сообщений. Одним из ключевых протоколов взаимодействия выступает STOMP, что делает интеграцию с JavaScript-клиентами через STOMP.js прямолинейной и предсказуемой.
HornetQ реализует модель брокера сообщений с разделением на адреса (addresses) и очереди (queues). Адрес выступает логической точкой публикации, а очередь — конкретным потребителем сообщений. При использовании STOMP поверх HornetQ происходит трансляция STOMP-команд в внутренние операции брокера.
Основные компоненты:
STOMP-клиент, подключающийся через WebSocket или TCP, не взаимодействует напрямую с очередями HornetQ. Он работает с абстракцией destination, которая на стороне брокера преобразуется в address/queue mapping.
Конфигурация STOMP acceptor обычно задаётся в
hornetq-configuration.xml. Пример логической
конфигурации:
<acceptors>
<acceptor name="stomp-acceptor">
tcp://0.0.0.0:61613?protocols=STOMP
</acceptor>
</acceptors>
В некоторых конфигурациях используется мультипротокольный acceptor:
<acceptor name="netty">
tcp://0.0.0.0:61616?protocols=CORE,STOMP,AMQP
</acceptor>
Ключевым моментом является параметр protocols=STOMP,
который активирует STOMP codec внутри Netty pipeline.
STOMP (Simple Text Oriented Messaging Protocol) представляет собой текстовый протокол поверх TCP/WebSocket. Основные операции:
HornetQ интерпретирует destination следующим образом:
/queue/name → point-to-point очередь/topic/name → pub-sub модельSTOMP.js используется как клиентская реализация STOMP поверх WebSocket или TCP-over-proxy.
Базовое подключение:
import { Client } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'ws://localhost:61614/stomp',
reconnectDelay: 5000,
debug: (msg) => console.log(msg)
});
client.onConn ect = (frame) => {
console.log('Connected:', frame.headers);
client.subscribe('/queue/test', (message) => {
const body = message.body;
console.log('Received:', body);
});
};
client.activate();
В случае HornetQ важно, чтобы был включён WebSocket STOMP endpoint (часто через proxy или servlet container).
client.publish({
destination: '/queue/test',
body: JSON.stringify({
type: 'event',
payload: {
id: 123,
status: 'ok'
}
})
});
HornetQ маршрутизирует сообщение в очередь test,
создавая binding между address /queue/test и
соответствующей queue instance.
STOMP.js поддерживает несколько режимов подписки, которые напрямую влияют на поведение HornetQ:
Сообщение автоматически подтверждается после доставки:
client.subscribe('/queue/test', (message) => {
console.log(message.body);
}, { ack: 'auto' });
Ручное подтверждение доставки:
client.subscribe('/queue/test', (message) => {
console.log(message.body);
message.ack();
}, { ack: 'client' });
HornetQ удерживает сообщение в unacknowledged state до получения ACK-фрейма.
Позволяет подтверждать каждое сообщение независимо:
client.subscribe('/queue/test', (message) => {
message.ack();
}, { ack: 'client-individual' });
HornetQ поддерживает транзакционные сессии STOMP. В STOMP.js это выражается через headers:
client.begin('tx1');
client.publish({
destination: '/queue/test',
body: 'message in transaction',
headers: { transaction: 'tx1' }
});
client.commit('tx1');
При rollback сообщение не фиксируется в очереди.
STOMP поддерживает heartbeat механизм для контроля соединения:
const client = new Client({
brokerURL: 'ws://localhost:61614/stomp',
heartbeatIncoming: 10000,
heartbeatOutgoing: 10000
});
HornetQ использует heartbeat для очистки зависших сессий и освобождения consumer lock.
После получения STOMP SEND:
MULTICAST соответствует topic-модели, ANYCAST — queue-модели.
HornetQ поддерживает приоритеты через STOMP headers:
client.publish({
destination: '/queue/test',
body: 'high priority message',
headers: {
priority: 9
}
});
Приоритет влияет на порядок доставки внутри очереди, но не гарантирует абсолютную сортировку при высокой конкуренции consumers.
TTL задаётся через header:
client.publish({
destination: '/queue/test',
body: 'temporary message',
headers: {
'expires': Date.now() + 60000
}
});
HornetQ удаляет сообщение после истечения времени жизни при отсутствии доставки.
STOMP-подписчики на одну очередь в HornetQ работают в режиме конкурирующих consumers. Сообщение доставляется только одному из подписчиков:
Типичные STOMP ошибки:
message: malformed frame — неправильный формат STOMP
frameaccess denied — отсутствие прав на destinationno route — отсутствие binding между address и
queueconsumer closed — разрыв подпискиSTOMP.js позволяет отслеживать ошибки:
client.onStompEr ror = (frame) => {
console.error('Broker error:', frame.body);
};
STOMP.js использует внутренний буфер outbound frames. При высокой нагрузке:
maxWebSocketFrameSize на стороне
брокераHornetQ, в свою очередь, оптимизирует throughput через batching и asynchronous IO.
/topic/notifications/queue/jobsSTOMP frame:
SEND
destination:/queue/test
content-type:text/plain
hello
преобразуется в internal message:
Далее сообщение попадает в paging store при необходимости.
HornetQ поддерживает:
STOMP.js передаёт credentials:
client.connectHeaders = {
login: 'user',
passcode: 'password'
};
При использовании WebSocket:
HornetQ в классической конфигурации чаще использует TCP STOMP, WebSocket добавляется через внешние компоненты.
При разрыве соединения: