我无法真正理解在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;
}
}
除了事实上现在要抛出我的例外情况要困难得多,我真的没有看到消息队列的好处......
有人可以开导我吗?
答案 0 :(得分:2)
在极少数情况下,您需要以先进/先出的方式串行处理命令,队列是实现此目的的简单方法。除此之外,我认为使用内存中队列处理命令没有任何实际好处。
在SOA场景中,使用排队技术(MSMQ,RabbitMQ等)非常有用,因为它允许持久的消息传递并增强系统可靠性。即使接收端点已关闭,该命令仍可排队等待,并在系统重新联机时准备就绪。
您的评论现在更难以抛出异常在这些情况下绝对正确,因为端点现在需要发送确认或错误以让客户端知道命令失败或成功。然而,拥有一个更强大的系统的好处通常超过这个轻微的不便。
答案 1 :(得分:1)
在大多数情况下,您不需要总线来执行命令。如果您因某些原因需要异步命令,我建议您仅使用命令总线。如果你不使用总线,那么处理命令就不那么复杂了。
CQRS没有说您需要使用总线来执行命令或事件。在CQRS中注意到您的命令和事件需要是异步的。
如果使用总线,则需要在发送命令之前验证命令。如果他们失败了,就像你说的那样,将更难以与客户沟通。你可以通过提出一些说明命令失败的事件来做到这一点,但直接向客户端返回一些东西要容易得多。