Персистентность сообщений в системах STOMP определяется сочетанием поведения брокера сообщений и корректной работой клиента, который отправляет и подтверждает получение сообщений. Сам протокол STOMP сам по себе не гарантирует сохранность данных, он лишь задаёт формат взаимодействия, тогда как сохранение сообщений реализуется на стороне брокеров (RabbitMQ, ActiveMQ, Apollo, Artemis и других).
Персистентность начинается с конфигурации очередей и сообщений на сервере. Брокер определяет, будет ли сообщение сохранено на диск или останется в памяти.
Ключевые механизмы:
В большинстве брокеров STOMP используется поверх JMS-подобной модели, где устойчивость достигается комбинацией флагов очереди и заголовков сообщений.
При отправке сообщения через STOMP.js важен заголовок, который указывает брокеру сохранять сообщение на диск.
client.publish({
destination: "/queue/orders",
body: JSON.stringify({ id: 1, status: "created" }),
headers: {
persistent: "true"
}
});
Значение persistent: "true" интерпретируется брокером
как необходимость сохранить сообщение. Без этого заголовка сообщение
может быть обработано как volatile и потеряться при сбое.
Важно учитывать, что поддержка этого заголовка зависит от конкретного брокера. Некоторые системы игнорируют его, если очередь не настроена как durable.
Персистентность различается в зависимости от модели маршрутизации:
Очереди (Queue) Сообщение хранится до тех пор, пока не будет доставлено одному потребителю. При включённой персистентности сообщение сохраняется на диске до подтверждения обработки.
Топики (Topic) Сообщение рассылается всем активным подписчикам. Персистентность здесь работает только в сочетании с durable subscription, иначе сообщения теряются при отсутствии подписчиков.
STOMP.js подписка создаётся через subscribe, и именно
здесь определяется поведение доставки.
client.subscribe("/queue/orders", (message) => {
const payload = JSON.parse(message.body);
console.log(payload);
});
По умолчанию подписка не гарантирует сохранность сообщений при разрыве соединения. Если соединение теряется, непринятые сообщения могут быть утрачены, если не используется подтверждение (ack) и устойчивые очереди.
Персистентность доставки тесно связана с механизмом подтверждений. STOMP поддерживает несколько режимов:
auto — подтверждение происходит автоматически при
доставкеclient — подтверждение выполняется вручнуюclient-individual — подтверждение каждого сообщения
отдельноПример с ручным подтверждением:
const subscription = client.subscribe(
"/queue/orders",
(message) => {
const data = JSON.parse(message.body);
processOrder(data);
message.ack();
},
{ ack: "client" }
);
Если сообщение не подтверждено, брокер может повторно доставить его после восстановления соединения. Это создаёт механизм гарантированной доставки поверх персистентного хранения.
Персистентность не ограничивается сохранением сообщений. Важной частью является поведение при сбоях:
STOMP.js не устраняет проблему дубликатов, поэтому логика обработки должна быть идемпотентной.
Для топиков используется механизм устойчивых подписок. Он требует явного идентификатора подписки.
client.subscribe(
"/topic/news",
(message) => {
console.log(JSON.parse(message.body));
},
{
id: "news-subscription-1",
persistent: "true"
}
);
На стороне брокера создаётся сохранённая подписка, которая продолжает получать сообщения после восстановления соединения. При этом сообщения, отправленные во время отсутствия подписчика, могут быть накоплены, если брокер поддерживает store-and-forward модель.
Жизненный цикл персистентного сообщения включает несколько этапов:
В брокерах с высокой надёжностью (например, RabbitMQ с persistent messages и durable queues) используется журналирование, позволяющее восстановить очередь после падения процесса.
Некоторые брокеры поддерживают STOMP-транзакции, которые группируют отправку сообщений и подтверждения.
client.begin("tx1");
client.publish({
destination: "/queue/orders",
body: "order-1",
headers: { transaction: "tx1" }
});
client.commit("tx1");
Если транзакция не подтверждена через commit, сообщения
не считаются доставленными, даже если они были отправлены в рамках
сессии. Это усиливает гарантию атомарности доставки.
Персистентность в связке с STOMP.js проявляется при нестабильных соединениях:
STOMP.js обычно требует ручного восстановления подписок:
client.onConn ect = () => {
client.subscribe("/queue/orders", handleMessage, { ack: "client" });
};
Персистентная доставка не исключает повторов. Причины:
Поэтому обработка сообщений должна учитывать уникальные идентификаторы:
const processed = new Set();
function handleMessage(message) {
const data = JSON.parse(message.body);
if (processed.has(data.id)) return;
processed.add(data.id);
process(data);
message.ack();
}
Персистентность в STOMP.js зависит от внешней инфраструктуры:
persistent не является универсальным
стандартомЭти различия делают поведение системы конфигурируемым, а не фиксированным на уровне клиента.