Для отправки сообщения клиенту с возможностью отмены транзакции в Java я бы применил паттерн Outbox.
-
Database transaction:
- Сообщение сохраняется в специальную "outbox" таблицу в той же транзакции, что и основная логика обработки.
- Если транзакция откатывается из-за ошибки в бизнес-логике, запись в таблице outbox не фиксируется, что предотвращает отправку сообщения.
-
Outbox Processor:
- Отдельный процесс (например, фоновый демон или планировщик) периодически опрашивает таблицу outbox на наличие новых, неотправленных сообщений.
- Этот процесс получает сообщения из базы данных.
- Отправляет сообщения клиенту (например, по HTTP, через очередь сообщений, WebSocket и т.д.).
- При успешной отправке сообщения помечается как отправленное в таблице outbox или удаляется.
-
Idempotency:
- Важно, чтобы обработчик на стороне клиента был идемпотентным, чтобы повторная отправка сообщения (в случае сбоев в Outbox Processor) не приводила к нежелательным последствиям.
Пример структуры таблицы outbox:
| Поле | Тип | Описание |
|---|
| id | UUID | Уникальный идентификатор |
| payload | JSON | Содержание сообщения |
| type | VARCHAR | Тип сообщения (например, "order_created") |
| created_at | TIMESTAMP | Время создания записи |
| processed_at | TIMESTAMP | Время обработки (NULL, если не обработано) |
| status | VARCHAR | Статус (например, "PENDING", "SENT", "FAILED") |
Пример кода (псевдокод):
java
java
Таким образом, транзакционная запись в outbox гарантирует, что сообщение будет отправлено клиенту только в случае успешного завершения основной бизнес-транзакции, обеспечивая согласованность данных.