|

Реализация паттерна Saga с использованием программы 1С и RabbitMQ для управления распределенными транзакциями


Содержание:

  1. Проблема: Почему обычные транзакции не работают при работе в системе 1С
  2. Решение: Паттерн Saga
  3. Реализация саги “Оформление заказа” с системой программ 1С и RabbitMQ (Хореография)

В мире, где 1С интегрируется с десятками внешних и внутренних сервисов — от CRM и складских систем до банковских шлюзов и служб доставки — возникает фундаментальная проблема. Как обеспечить целостность бизнес-операции, которая затрагивает несколько независимых систем? Классическая транзакция СУБД (ACID), к которой мы привыкли в рамках одной базы 1С, здесь бессильна. Нельзя просто запустить транзакцию в 1С, изменить данные в ней, потом в базе данных сайта, потом в системе логистики, и в конце сделать общий COMMIT или ROLLBACK.

Эта проблема называется проблемой распределенной транзакции. И для ее решения был придуман паттерн “Сага” (Saga).

Проблема: Почему обычные транзакции не работают при работе в системе 1С

Представим простой, но показательный бизнес-процесс: оформление и отгрузка заказа. Он состоит из трех шагов, каждый из которых выполняется отдельным сервисом:

  1. Сервис Заказов (на базе 1С): Создает документ “Заказ клиента”.
  2. Платежный сервис (внешний): Списывает деньги с карты клиента.
  3. Складской сервис (WMS): Резервирует и готовит товар к отгрузке.

В идеальном мире все три шага успешны. Но что, если второй шаг (оплата) прошел успешно, а третий (резерв на складе) — нет, потому что товара не оказалось в наличии? Мы списали деньги, но отгрузить товар не можем. Система находится в неконсистентном состоянии. Отменить транзакцию в Складском сервисе просто, но как откатить уже списанные деньги в платежном сервисе и созданный заказ в 1С?

Решение: Паттерн Saga

Сага — это последовательность локальных транзакций в каждом из сервисов. Ключевая идея в том, что для каждой локальной транзакции, которая что-то изменяет в системе, должна существовать компенсирующая транзакция.

  • Локальная транзакция: Обычная ACID-транзакция внутри одного сервиса (например, проведение документа в 1С).
  • Компенсирующая транзакция: Операция, которая отменяет действие локальной транзакции. Например, для “Списать деньги” компенсацией будет “Вернуть деньги”. Для “Зарезервировать товар” — “Снять резерв с товара”.

Если любой шаг в саге завершается неудачей, система запускает компенсирующие транзакции для всех предыдущих, уже успешно выполненных шагов, в обратном порядке. Это позволяет вернуть всю систему в консистентное состояние, эквивалентное тому, которое было до начала операции. Это не настоящий откат (данные уже были изменены и потом изменены снова), а семантическая отмена.

Существует два основных способа координации саг:

  1. Хореография (Choreography): Децентрализованный подход. Каждый сервис после выполнения своей работы публикует событие в общую шину (наш RabbitMQ). Другие сервисы слушают эти события и знают, когда им нужно начать свою работу.
  2. Оркестрация (Orchestration): Централизованный подход. Существует специальный сервис-“оркестратор”, который управляет всем процессом. Он говорит сервису А сделать шаг 1, ждет ответа, затем говорит сервису Б сделать шаг 2 и так далее. Если что-то идет не так, он же отдает команды на запуск компенсирующих транзакций.

Хореография часто выглядит более естественной для событийной архитектуры с RabbitMQ, поэтому рассмотрим ее.

Реализация саги “Оформление заказа” с системой программ 1С и RabbitMQ (Хореография)

Нам понадобится RabbitMQ с настроенным обменником (Exchange), например, типа topic с именем order processing. Сервисы будут обмениваться сообщениями-событиями.

Шаг 1: Создание заказа (1С)

  • Пользователь в 1С нажимает “Оформить заказ”.
  • 1С выполняет локальную транзакцию: создает документ Заказ клиента со статусом “Создан”.
  • После успешной записи документа 1С публикует в RabbitMQ событие OrderCreated с данными заказа (ID заказа, сумма, состав).
    • Технически: сообщение отправляется в exchange order processing с routing key order.created.

Шаг 2: Обработка платежа (Платежный сервис)

  • Платежный сервис подписан на события с ключом order.created.
  • Он получает сообщение, выполняет свою локальную транзакцию: обращается к банковскому шлюзу и списывает деньги.
  • Успех: Сервис публикует событие PaymentProcessed (ключ payment.processed).
  • Неудача: Сервис публикует событие PaymentFailed (ключ payment.failed).

Шаг 3: Резервирование на складе (WMS)

  • Складской сервис подписан на события payment.processed.
  • Получив его, он выполняет свою локальную транзакцию: резервирует товар.
  • Успех: Публикует событие StockReserved (ключ stock.reserved). На этом счастливый путь саги завершен.
  • Неудача: Публикует событие StockReservationFailed (ключ stock.reservation.failed).

Теперь самое главное — обработка сбоев (компенсация)

Предположим, WMS не смог зарезервировать товар и опубликовал событие StockReservationFailed.

  • Платежный сервис тоже должен быть подписан на это событие (stock.reservation.failed). Получив его, он запускает свою компенсирующую транзакцию: выполняет операцию возврата денег клиенту. После успеха он может опубликовать событие PaymentRefunded (ключ payment.refunded).
  • Сервис заказов 1С также слушает события о неудачах (stock.reservation.failed или payment.failed). Получив любое из них, он запускает свою компенсирующую транзакцию: находит исходный заказ и меняет его статус на “Отменен (нет товара)” или “Отменен (ошибка оплаты)”.

Роль RabbitMQ в этом процессе:

  • Надежная доставка: RabbitMQ выступает гарантом того, что событие будет доставлено. Настроив очереди и сообщения как durable, мы не потеряем их при перезапуске брокера. Механизм подтверждения (ack) гарантирует, что сервис-обработчик удалит сообщение из очереди только после того, как полностью его обработает.
  • Гибкая маршрутизация: Использование topic exchange позволяет сервисам подписываться только на те события, которые им интересны. 1С может слушать payment.failed и stock.reservation.failed, а WMS — только payment.processed. Это и есть слабая связность в действии.
  • Асинхронность: Сервисы не ждут друг друга. 1С опубликовала событие и забыла про него, продолжая работать. Это делает систему отзывчивой и устойчивой к временной недоступности отдельных компонентов.

Паттерн Saga — это сложная, но чрезвычайно мощная концепция. Он заставляет переосмыслить подход к бизнес-операциям, смещая фокус с технических ACID-транзакций на логическую целостность всего процесса.

Реализация саг требует тщательного проектирования, особенно в части идемпотентности и логики компенсаций. Однако, используя надежный транспорт в лице RabbitMQ, можно построить систему, которая способна автоматически восстанавливаться после сбоев, сохраняя данные в консистентном состоянии.

Специалист компании ООО “Кодерлайн”,

Астанов Артём


Помогла ли вам статья? Оставьте свой комментарий:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Блог про 1С:Предприятие

Copyright © 2024 TopKoder

Мы занимаемся внедрением и обслуживанием программных продуктов 1С.