Содержание:
- Проблема: Почему обычные транзакции не работают при работе в системе 1С
- Решение: Паттерн Saga
- Реализация саги “Оформление заказа” с системой программ 1С и RabbitMQ (Хореография)
В мире, где 1С интегрируется с десятками внешних и внутренних сервисов — от CRM и складских систем до банковских шлюзов и служб доставки — возникает фундаментальная проблема. Как обеспечить целостность бизнес-операции, которая затрагивает несколько независимых систем? Классическая транзакция СУБД (ACID), к которой мы привыкли в рамках одной базы 1С, здесь бессильна. Нельзя просто запустить транзакцию в 1С, изменить данные в ней, потом в базе данных сайта, потом в системе логистики, и в конце сделать общий COMMIT или ROLLBACK.
Эта проблема называется проблемой распределенной транзакции. И для ее решения был придуман паттерн “Сага” (Saga).
Проблема: Почему обычные транзакции не работают при работе в системе 1С
Представим простой, но показательный бизнес-процесс: оформление и отгрузка заказа. Он состоит из трех шагов, каждый из которых выполняется отдельным сервисом:
- Сервис Заказов (на базе 1С): Создает документ “Заказ клиента”.
- Платежный сервис (внешний): Списывает деньги с карты клиента.
- Складской сервис (WMS): Резервирует и готовит товар к отгрузке.
В идеальном мире все три шага успешны. Но что, если второй шаг (оплата) прошел успешно, а третий (резерв на складе) — нет, потому что товара не оказалось в наличии? Мы списали деньги, но отгрузить товар не можем. Система находится в неконсистентном состоянии. Отменить транзакцию в Складском сервисе просто, но как откатить уже списанные деньги в платежном сервисе и созданный заказ в 1С?
Решение: Паттерн Saga
Сага — это последовательность локальных транзакций в каждом из сервисов. Ключевая идея в том, что для каждой локальной транзакции, которая что-то изменяет в системе, должна существовать компенсирующая транзакция.
- Локальная транзакция: Обычная ACID-транзакция внутри одного сервиса (например, проведение документа в 1С).
- Компенсирующая транзакция: Операция, которая отменяет действие локальной транзакции. Например, для “Списать деньги” компенсацией будет “Вернуть деньги”. Для “Зарезервировать товар” — “Снять резерв с товара”.
Если любой шаг в саге завершается неудачей, система запускает компенсирующие транзакции для всех предыдущих, уже успешно выполненных шагов, в обратном порядке. Это позволяет вернуть всю систему в консистентное состояние, эквивалентное тому, которое было до начала операции. Это не настоящий откат (данные уже были изменены и потом изменены снова), а семантическая отмена.
Существует два основных способа координации саг:
- Хореография (Choreography): Децентрализованный подход. Каждый сервис после выполнения своей работы публикует событие в общую шину (наш RabbitMQ). Другие сервисы слушают эти события и знают, когда им нужно начать свою работу.
- Оркестрация (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, можно построить систему, которая способна автоматически восстанавливаться после сбоев, сохраняя данные в консистентном состоянии.
Специалист компании ООО “Кодерлайн”,
Астанов Артём
Добавить комментарий