State Machine и Хореография
В прошлых постах мы разобрали, что такое хореография и как ее реализовывать. А теперь соединим хореографию с паттерном State Machine. Это позволит построить нам прозрачную и управляемую архитектуру.
При использовании хореографии логику взаимодействия между частями системы координируют сами участники взаимодействия. Но у каждого участника при этом свой жизненный цикл бизнес-логики/бизнес-домена. Если событий, на которые должен реагировать участник хореографии, становится больше 2-3, то логика обработки событий становится очень запутанной. В этом случае нам поможет использование State Machine для реакции на события. Это позволит согласовать внутреннее состояние сервиса с событиями в системе.
Что дает применение хореографии:
- Реализация слабой связанности между компонентами системы.
- Делает систему гибкой и масштабируемой.
Что дает применение State Machine:
- Определяет допустимые переходы между состояниями.
- Изолирует бизнес-логику от реализации.
- Повышает читаемость кода.
- Повышает тестируемость.
State Machine для управления состоянием на основе событий
Рассмотрим использование State Machine для управления состоянием, когда сервис участвует в обработке событий. Примерная схема обработки событий:
Представим, что у нас есть сервис обработки заказов. Заказ (Order) может пребывать в следующих состояниях и переходах:
В соответствии с этой диаграммой состояния заказов и события выраженные в коде:
Теперь настроим State Machine:
Здесь OrderPaymentCompleteAction, OrderShipmentStartedAction и OrderDeliveredAction — действия, которые будут выполняться при переходе в соответствующее состояние. Именно в них мы будем реализовывать бизнес-логику. Для иллюстрации действия просто будут выводить в лог сообщение о том, что действие выполняется.
При создании заказа мы создаем State Machine и сохраняем необходимые данные в контекст. После старта и обработки сохраняем сам контекст State Machine.
Для сохранения состояния State Machine используем StateMachinePersister. Чтобы реализовать поведение сохранения и загрузки состояния State Machine, нам нужно реализовать интерфейс StateMachinePersist:
Но чтобы он заработал, нам необходимо также определить bean (без этого не будет сохраняться) StateMachinePersister:
Сам процесс обработки событий можно завернуть в отдельный сервис, который будет восстанавливать состояние State Machine на основе идентификатора заказа, пересылать ей сообщение и сохранять состояние:
События могут как отправляться через очередь сообщений, так и через REST API. Также в зависимости от выбранной архитектуры, для каждого события может быть как отдельный обработчик, так и один обработчик для всех событий. Для примера я реализовал обработку событий через REST API с единственным методом, принимающим тип события и данные события.
Преимущества подхода
- При использовании State Machine мы централизуем логику обработки событий внутри каждого сервиса.
- State Machine берет на себя обязанность по управлению и валидации переходов из одного состояния в другое, тем самым уменьшает вероятность ошибки.
- Сервисы все также слабо связаны благодаря использованию хореографии.
Используя State Machine, мы берем лучшее из двух миров: независимость и разделение ответственности между участниками процесса (хореография) и централизованную логику переходов между состояниями самих участников.
Исходные коды доступны по ссылке.
Подписывайся на мой telegram-канал