This plugin provides you tools for both sending commands to and consuming from a queue.
To setup queueing on the client side, simply pass the QueueMiddleware to the Command Bus. After that you queue commands by implementing the
League\Tactician\Bernard\QueueableCommand interface (Alternatively you can implement
Bernard\Message, see explanation later). Others will be passed to the next middleware in the chain.
use Bernard\Producer; use League\Tactician\Bernard\QueueMiddleware; use League\Tactician\CommandBus; // $producer = new Producer(/*...*/); $queueMiddleware = new QueueMiddleware($producer); $commandBus = new CommandBus([$queueMiddleware]); $commandBus->handle($command);
$producer variable in the example is a
Bernard\Producer instance. See the official documentation for details.
On the other side of the message queue you must set up a consumer:
use Bernard\Consumer; use Bernard\Router\SimpleRouter; use League\Tactician\Bernard\Receiver\SingleBusReceiver; use League\Tactician\CommandBus; use Symfony\Component\EventDispatcher\EventDispatcher; // Create the command bus that receives the queued commands $commandBus = new CommandBus([/* middlewares go here */]); // Wire the command bus into Bernard's routing system $receiver = new SameBusReceiver($commandBus); $router = new SimpleRouter(); $router->add('League\Tactician\Bernard\QueueableCommand', $receiver); // Finally, create the Bernard consumer that runs through the pending queue $consumer = new Consumer($router, new EventDispatcher()); $consumer->consume($queue);
The plugin tries to follow Bernard’s logic as close as possible. To learn more about how consuming and routers work, check the official documentation for details.
Receiver is a term used in both command pattern and the message terminology. In this case a receiver is a callable passed to the Router. The Router routes all messages to a receiver (or returns with error if no receiver is registered for a messsage). There are two receivers implemented by this plugin:
SameBusReceiver: This receiver should be used when the same command bus is used for the producer and the consumer side. It prevents a command from being requeued (causing an infinite loop).
SeparateBusReceiver: Use this receiver in any other cases.
Bernard provides an interface for messages to implement. If you implement only this interface, it is totally fine. The reason we have our own interface for queueable commands is to ease the separation of commands sent by Tactician and other messages received by the consumer (so you can register a separate receiver for commands sent by Tactician). In theory, you can use your consumer with not just Tactician, but with any custom logic.