Я не могу понять преимущества команд в очереди в CommandBus.
Вот моя очень простая реализация CommandBus:
class CommandBus implements ICommandBus
{
private $handlerLocator;
public function __construct(ICommandHandlerLocator $handlerLocator)
{
$this->handlerLocator = $handlerLocator;
}
public function handle(ICommand $command)
{
$handler = $this->handlerLocator->getHandlerInChargeFor($command);
try{
$handler->handle($command);
}
catch(\Exception $e) {
throw $e;
}
}
}
Эта реализация на самом деле оформлена в TransactionnalCommandBus, в котором сохраняются команды в виде базы данных журналов, но, поскольку это не предмет моего вопроса, я не буду здесь это показывать.
Теперь давайте сосредоточимся на очереди CommandBus:
class QueuingCommandBus implements ICommandBus
{
private $innerCommandBus;
private $commandQueue = array();
private $isHandling = false;
public function __construct(CommandBus $commandBus)
{
$this->innerCommandBus = $commandBus;
}
public function handle(ICommand $command)
{
$this->commandQueue[] = $command;
if($this->isHandling)
{
return;
}
while($command = array_shift($this->commandQueue))
{
$this->isHandling = true;
$this->innerCommandBus->handle($command);
}
$this->isHandling = false;
}
}
Кроме того, теперь гораздо сложнее отбросить мои исключения, я действительно не вижу преимуществ очереди сообщений …
Может кто-то может просветить меня?
В редких, специфических случаях, когда вам нужно обрабатывать команды последовательно, в порядке «первым пришел — первым вышел», очередь — это простой способ сделать это. Помимо этого, я не вижу реального преимущества использования очереди в памяти для обработки команд.
В сценарии SOA использование технологий организации очередей (MSMQ, RabbitMQ и т. Д.) Может быть чрезвычайно полезным, так как оно обеспечивает длительный обмен сообщениями и повышает надежность системы. Даже если принимающая конечная точка не работает, команда все еще может быть поставлена в очередь и готова к работе, когда система вернется в оперативный режим.
Ваш комментарий теперь гораздо сложнее бросить мои исключения в этих случаях абсолютно верно, поскольку конечной точке теперь нужно отправить ack или ошибку, чтобы клиент узнал, что команда завершилась неудачно или успешно. Однако преимущества более надежной системы обычно перевешивают это незначительное неудобство.
В большинстве случаев вам не нужна шина для ваших команд. Я бы порекомендовал вам использовать командную шину, только если по какой-то причине ваши команды должны быть асинхронными. Если вы не используете шину, то обработка ваших команд будет менее сложной.
Ничто в CQRS не говорит о том, что вам нужно использовать шину для ваших команд или событий. В CQRS отмечается, что ваши команды и события должны быть асинхронными.
Если вы используете шину, то вам нужно проверить свои команды перед их отправкой. Если они потерпят неудачу, то, как вы говорите, будет намного сложнее сообщить об этом клиенту. Вы можете сделать это, вызвав какое-то событие, сообщающее, что команда завершилась неудачно, но было бы намного проще просто просто что-то вернуть клиенту.