Как получить вновь созданный объект с помощью асинхронной команды (CQRS) в том же процессе php?

Я реализую приложение 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 единственное? Каковы приемлемые реализации решений? Или какой момент я упускаю? :)


person Tom    schedule 19.02.2017    source источник
comment
CQRS лучше всего работает с DDD и Event Sourcing. Вы пробовали это?   -  person Constantin Galbenu    schedule 20.02.2017


Ответы (1)


Самое простое решение для получения информации об идентификаторе созданного агрегата/сущности — добавить его в команду. Таким образом, интерфейс генерирует идентификатор и передает его с данными. Но чтобы это решение работало, вам нужно использовать uuid вместо обычных целых чисел базы данных, иначе вы можете столкнуться с дублированием идентификаторов на стороне базы данных.
Если команда является асинхронной и выполняет такие трудоемкие действия, вы можете Обязательно публикуйте события от потребителя. Таким образом, клиент через.e.g. веб-сокеты получают информацию в режиме реального времени. Либо спрашивайте у бэкэнда о существовании заказа с id из команды, время от времени и при наличии ресурса перенаправляйте его на нужную страницу.

person Dariss    schedule 19.02.2017
comment
Мне почему-то не нравится идея, что сервис, который что-то делает и должен использовать команду для создания нового объекта (кстати, просто), должен заботиться о создании идентификатора этого объекта. Как я показал в своем примере, мне бы хотелось, чтобы каждая команда создавалась со своим GUID, и я мог бы получить его из него. Тогда у меня есть id команды, и я знаю, что слушать. Но как точно можно реализовать прослушивание в моем примере? Он должен блокироваться, поэтому не нужно активно спрашивать о существовании. - person Tom; 19.02.2017
comment
Websocket звучит хорошо, я нашел React PHP reactphp.org, но я все еще не понимаю, как применить к моему примеру . Об этом так мало, когда я ищу в Google. Это займет некоторое время. Было бы хорошо, если бы кто-нибудь мог уточнить это в ответ. :) - person Tom; 19.02.2017
comment
Как вы думаете, почему этот сервис должен отвечать за генерацию идентификатора? В любом случае вы предоставляете его пользователю, это не скрытое значение, о котором пользователь не должен знать. - person Dariss; 20.02.2017
comment
О веб-сокетах. Взгляните на реализации шаблона подписки на публикацию. - person Dariss; 20.02.2017