Я реализую приложение PHP с CQRS.
Допустим, у меня есть CreateOrderCommand
и когда я делаю
$command = new CreateOrderCommand(/** some data**/);
$this->commandBus->handle($command);
CommandBus теперь просто передайте команду CreateOrderCommandHandler
Класс так же легко, как:
abstract class SimpleCommandBus implements CommandBus
{
/** @var ICommandHandlerLocator */
protected $locator;
/**
* Executes command
*
* @param Command $command
*/
public function handle(Command $command)
{
$handler = $this->locator->getCommandHandler($command);
$handler->handle($command);
}
}
Все нормально.
Но обработка — пустой метод, поэтому я ничего не знаю о прогрессе или результате. Что я могу сделать, чтобы, например, уволить CreateOrderCommand
и затем в том же процессе получить вновь созданный идентификатор объекта (вероятно, с некоторым пассивным ожиданием его создания)?
public function createNewOrder(/** some data**/){
$command = new CreateOrderCommand(/** some data**/);
$this->commandBus->handle($command);
// something that will wait until command is done
$createdOrder = // some magic that retrieves some adress to result data
return $createdOrder;
}
И чтобы ближе понять, что может обеспечить CQRS, командная шина должна иметь возможность RabbitMqCommandBus
реализация, которая просто сериализует команду и отправляет ее в очередь кролика.
Таким образом, тогда процесс, который, наконец, обрабатывает команду, может быть неким работающим потребителем, и здесь требуется какая-то связь между процессами — чтобы иметь возможность каким-то образом информировать исходный пользовательский процесс от потребителя, что это делается (с некоторой информацией, например, идентификатором новая сущность).
Я знаю, что есть решение с GUID — я мог пометить команду с GUID. Но что потом:
public function createNewOrder(/** some data**/){
$command = new CreateOrderCommand(/** some data**/);
$this->commandBus->handle($command);
$guid = $command->getGuid();
// SOME IMPLEMENTATION
return $createdOrder;
}
НЕКОТОРЫЕ ОСУЩЕСТВЛЕНИЯ должны выполнить некоторую проверку событий (поэтому мне нужно также реализовать некоторую систему событий) по команде с определенным GUID, чтобы иметь возможность, например, отображать ход выполнения или включать OrderCreatedEvent
просто верните это удостоверение личности, которое я получу от этого события. Потребительский процесс, который асинхронно обрабатывает команду, может, например, передать события кролику, а пользовательский клиент получит их и сделает правильный ответ (например, выполнение эха, возврат вновь созданного объекта).
Но как это сделать? И единственное ли решение с GUID? Каковы приемлемые реализации решений? Или какой момент я упускаю? 🙂
Самое простое решение для получения информации об идентификаторе созданного агрегата / сущности — добавить ее в команду. Таким образом, внешний интерфейс генерирует идентификатор и передает его вместе с данными. Но чтобы это решение работало, вам нужно использовать uuid вместо обычных целых чисел в базе данных, в противном случае вы можете столкнуться с дублированием идентификаторов на стороне базы данных.
Если команда асинхронная и выполняет такие длительные действия, вы наверняка можете опубликовать события от потребителя. Таким образом, клиент через, например, websockets получает информацию в режиме реального времени.
Или спросите у бэкенда о наличии ордера с идентификатором из команды, время от времени и когда ресурс существует, перенаправьте его на нужную страницу.
Других решений пока нет …