Друкарня від WE.UA

Як гарантувати доставку подій у мікросервісах? Реальний підхід через Transactional Outbox у Spring Boot 🚀

Уявіть: користувач оформляє замовлення. Ви успішно зберігаєте його в базу, але повідомлення іншим сервісам не доходить через мережевий збій...
В результаті: продавець не знає про нове замовлення, рахунок не виставлений, а клієнт незадоволений.

Создать мем "плачущий кот, грустный кот мем, кот плачет мем" - Картинки -  Meme-arsenal.com
Це ти до Transactional Outbox 😸

Як це виправити раз і назавжди? Відповідь — Transactional Outbox.

Що таке Transactional Outbox?

Це простий і надійний принцип:

• В тій самій транзакції, де ми оновлюємо основні дані, ми також записуємо подію у спеціальну таблицю Outbox.

• А потім окремий процес читає ці події і відправляє їх у брокер (Kafka, RabbitMQ тощо).

Так ми гарантуємо: або все успішно, або нічого.

Реалізація

1. Створюємо таблицю для подій

CREATE TABLE outbox_event (
    id UUID PRIMARY KEY,
    order_id VARCHAR(255) NOT NULL,
    status VARCHAR(255) NOT NULL,
    payload JSONB NOT NULL,
    created_at TIMESTAMP NOT NULL,
    updated_at TIMESTAMP NOT NULL,
    processed BOOLEAN NOT NULL DEFAULT false
);

2. Пишемо Entity для OutboxEvent

import jakarta.persistence.*;
import java.time.LocalDateTime;
import java.util.UUID;

@Entity
@Table(name = "outbox_event")
public class OutboxEvent {

    @Id
    private UUID id;

    @Column(name = "order_id", nullable = false)
    private String orderId;

    @Column(nullable = false)
    private String status;

    @Column(columnDefinition = "jsonb", nullable = false)
    private String payload;

    @Column(name = "created_at", nullable = false, updatable = false)
    private LocalDateTime createdAt;

    @Column(name = "updated_at", nullable = false)
    private LocalDateTime updatedAt;

    @Column(nullable = false)
    private Boolean processed = false;

    // Getters and Setters

}

3. Пишемо репозиторій для OutboxEvent

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.UUID;

public interface OutboxEventRepository extends JpaRepository<OutboxEvent, UUID> {

    @Query(value = """
        SELECT * FROM outbox_event
        WHERE processed = false
        ORDER BY created_at
        FOR UPDATE SKIP LOCKED
        LIMIT :batchSize
        """, nativeQuery = true)
    List<OutboxEvent> findUnprocessedEventsForUpdate(@Param("batchSize") int batchSize);
}

Ти напевно здивований чому саме такий запит? Це на той випадок якщо твій сервіс задеплоєн на декілька інстансів, та необхідно уникнути конфліктів при читанні подій паралельно кількома інстансами. Завдяки SKIP LOCKED конкуренція між інстансами вирішується автоматично.

✅ Можна масштабувати горизонтально без страху дублювання або втрати повідомлень.

4. Запис основних даних і події в одній транзакції

@Transactional
public void createOrder(Order order) {
    orderRepository.save(order);

    OutboxEvent event = new OutboxEvent(
        UUID.randomUUID(),
        order.getId(),
        "OrderCreated",
        serialize(order)
    );

    outboxEventRepository.save(event);
}

5. Публікація подій за допомогою Scheduler

@Scheduled(fixedDelay = 5000)
@Transactional
public void publishOutboxEvents() {
    List<OutboxEvent> events = outboxEventRepository.findUnprocessedEventsForUpdate(10);

    for (OutboxEvent event : events) {
        messagePublisher.publish(event.getStatus(), event.getPayload());
        event.setProcessed(true);
    }
}

Практичні поради для продакшена

  • 🛡 Ідемпотентність: обробники подій мають бути ідемпотентними.

  • 🔁 Retry: якщо брокер тимчасово недоступний — передбачити повторні спроби.

  • 🧹 Очищення Outbox: налаштувати регулярне видалення або архівацію старих подій.

  • 🏎 Батчинг: обробляти події пачками для кращої продуктивності.

Transactional Outbox — це надійний фундамент для побудови консистентних, масштабованих і відмовостійких мікросервісів.

Правильна імплементація дозволяє тобі не боятись втрати події навіть у найскладніших розподілених середовищах.

Sacha Baron Cohen offers to pay tourists' mankini fines | The Times of  Israel
Борат одобряє 😉

Статті про вітчизняний бізнес та цікавих людей:

  • СТО чи самостійний ремонт?

    Кожен автовласник стикається з дилемою: виконувати ремонт автомобіля самостійно чи довірити роботу професіоналам на СТО. Це питання дуже актуальне у великих містах, де щільний трафік, сезонні погодні умови та інтенсивна експлуатація автомобіля вимагають регулярного обслуговування

    Теми цього довгочиту:

    Сто
  • Міфи про SEO: розвінчуємо хибні уявлення

    Навколо SEO роками накопичувалися хибні уявлення – від віри в миттєвий результат до спрощеного розуміння механіки пошуку. У результаті міфи про SEO заважають бізнесу реально оцінювати можливості органічного просування.

    Теми цього довгочиту:

    Seo
  • Доставка з Канади в Україну разом із Meest: особливості та переваги

    Щоб отримувати посилки та грошові перекази вигідним і безпечним способом, працює доставка з Канади в Україну від поштового оператора Meest.

    Теми цього довгочиту:

    Meest Canada
  • Секрети зонування: як правильно розмістити точкові світильники у квартирі-студії - розповіли в Rozetka

    У квартирі-студії освітлення виконує роль просторового інструменту, що задає функціональні межі без додаткових перегородок. Компактний формат приміщення потребує точного планування світлових сценаріїв. Саме тому в системах зонування часто використовують точкові світильники

    Теми цього довгочиту:

    Освітлення
  • П'ять причин, чому зараз ідеальний час для переходу на MacBook | Rozetka

    Вибір ноутбука сьогодні визначається не лише «залізом». Для багатьох користувачів головним стає не максимальна потужність у тестах, а комфорт щоденної роботи без збоїв і компромісів. Саме тому перехід на екосистему Apple дедалі частіше розглядають як надійне та практичне рішення

    Теми цього довгочиту:

    Macbook
Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Сергій Барабаш
Сергій Барабаш@sbarabash

663Прочитань
1Автори
12Читачі
На Друкарні з 30 березня

Більше від автора

Це також може зацікавити:

Коментарі (0)

Підтримайте автора першим.
Напишіть коментар!

Це також може зацікавити: