CRQS:排队命令的好处

CRQS : benefits of queuing commands

我无法真正理解在命令总线中对命令进行排队的好处。

这是我对命令总线的非常简单的实现:

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;
      }
  }

}

这个实现实际上在一个 TransactionalCommandBus 中得到了修饰,它在日志数据库中持久化命令,但因为这不是我的问题的重点,所以我不会在这里展示它。

现在让我们专注于排队 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;
    }
}

除了现在抛出异常变得更加困难之外,我真的看不出消息队列的好处...

谁能教教我?

在极少数特定情况下,您需要以 first-in/first-out 方式连续处理命令,队列是实现此目的的简单方法。除此之外,我看不到使用内存队列处理命令的真正好处。

在 SOA 场景中,使用队列技术(MSMQ、RabbitMQ 等)可以带来巨大好处,因为它允许持久消息传递并增强系统可靠性。即使接收端点已关闭,命令仍然可以排队等待系统重新联机时使用。

你的评论现在更难抛出我的异常在这些情况下是绝对正确的,因为端点现在需要发送确认或错误让客户端知道命令失败或成功。然而,拥有一个更强大的系统的好处通常会超过这个小小的不便。

在大多数情况下,您的命令不需要总线。如果您出于某种原因需要异步命令,我建议您只使用命令总线。如果您不使用总线,那么您的命令处理将不那么复杂。

关于 CQRS,没有任何内容表明您需要为您的命令或事件使用总线。在 CQRS 中注意到您的命令和事件需要异步。

如果您使用公交车,那么您需要在发送命令之前验证您的命令。如果他们失败了,正如您所说,将其传达给客户将变得更加困难。你可以通过引发一些事件说命令失败来做到这一点,但是直接向客户端 return 一些东西会容易得多。