Откат транзакции в STOMP.js является механизмом, позволяющим отменить все сообщения, отправленные в рамках транзакционного контекста, до момента их окончательного подтверждения брокером. При корректной реализации это обеспечивает атомарность набора операций: либо все сообщения фиксируются, либо ни одно из них не попадает в очередь. Такой подход критичен для сценариев, где частичная доставка данных недопустима — например, при синхронизации состояния, финансовых операциях или пакетной обработке событий.
Транзакции в STOMP основаны на идентификаторе транзакции, который связывает несколько кадров SEND в единый логический блок. Брокер, поддерживающий спецификацию STOMP (ActiveMQ, RabbitMQ с STOMP plugin, Apollo и др.), обрабатывает такие сообщения отложенно до момента получения команды завершения.
Ключевые особенности модели:
transaction id;transaction;COMMIT;STOMP.js реализует этот механизм через объект транзакции, предоставляя методы управления жизненным циклом.
Создание транзакции выполняется через клиентский объект соединения:
const tx = client.begin();
На уровне протокола отправляется frame:
BEGIN
transaction:tx-001
Идентификатор транзакции формируется клиентом или библиотекой и используется далее для привязки всех операций.
Важно учитывать, что транзакция существует только в рамках активного соединения. При разрыве соединения брокер автоматически отменяет незавершённые транзакции.
Каждое сообщение, отправляемое в рамках транзакции, должно содержать ссылку на её идентификатор:
client.publish({
destination: '/queue/orders',
body: JSON.stringify({ orderId: 123 }),
headers: {
transaction: tx.id
}
});
На уровне STOMP это превращается в:
SEND
destination:/queue/orders
transaction:tx-001
{"orderId":123}
Особенности поведения:
При множественных SEND в рамках одной транзакции сохраняется порядок отправки, но окончательная атомарность зависит от реализации брокера.
Откат выполняется через метод:
tx.abort();
или явный вызов:
client.abort(tx.id);
На уровне протокола формируется frame:
ABORT
transaction:tx-001
После получения ABORT брокер обязан:
Ключевое свойство отката — полное исключение следов транзакции из очередей. Это не частичный rollback, а полная отмена блока операций.
При ABORT:
Если часть сообщений уже была обработана брокером до получения ABORT (редкие случаи при нестандартных реализациях), возможны расхождения, что требует настройки уровня изоляции и проверки поддержки транзакций конкретным брокером.
Разные брокеры реализуют транзакции STOMP с вариациями:
Общие правила:
Некоторые брокеры используют журналирование транзакций, что влияет на производительность при частых откатах.
Откат транзакции применяется в ситуациях, где требуется строгая целостность:
Пример сценария:
const tx = client.begin();
try {
client.publish({
destination: '/queue/payments',
body: JSON.stringify({ amount: 100 }),
headers: { transaction: tx.id }
});
client.publish({
destination: '/queue/logs',
body: 'payment initiated',
headers: { transaction: tx.id }
});
tx.commit();
} catch (e) {
tx.abort();
}
При любой ошибке оба сообщения будут отменены.
Откат транзакции не всегда является тривиальной операцией и может сопровождаться рядом проблем:
Особое внимание требуется уделять таймаутам: если транзакция остаётся открытой слишком долго, брокер может принудительно её закрыть или очистить.
Также важно учитывать, что rollback не отменяет уже доставленные сообщения, если брокер нарушает спецификацию или используется нестандартная конфигурация доставки.
В STOMP.js управление откатом сводится к работе с объектом транзакции:
const tx = client.begin();
tx.abort();
или через клиент:
client.abort(tx.id);
Рекомендуется:
При высокой нагрузке транзакции следует использовать только там, где критична атомарность, так как каждая транзакция увеличивает нагрузку на брокер и снижает throughput очереди.
Поведение rollback тесно связано с ACK-моделью потребления: сообщения, отправленные в транзакции, не должны обрабатываться потребителями до её завершения, иначе нарушается гарантия целостности.