Skip to content

Latest commit

 

History

History
126 lines (100 loc) · 4.77 KB

routing.md

File metadata and controls

126 lines (100 loc) · 4.77 KB

Routing

You can define your message handlers like every service in Symfony. But you need to tell your message bus that a handler is a target for a message object.

There are two ways to route a message object to a handler. You can configure it using a tag at the handler definition or directly at the bus configuration.

The basis for both ways is the service definition of the handler

# app/config/services.yml
services:
    Acme\Command\RegisterUserHandler: ~

and a configured message bus:

# app/config/config.yml or (flex) config/packages/prooph_service_bus.yaml
prooph_service_bus:
    command_buses:
        acme_command_bus: ~

The command bus is used as example, handlers are routed to each bus (nearly) the same way.

Routing using tags

If you don't know about tags in Symfony please have a look at the official documentation.

To route a message to a specific handler, we just need to add a tag to its service definition:

# app/config/services.yml
services:
    Acme\Command\RegisterUserHandler:
        tags:
            - { name: 'prooph_service_bus.acme_command_bus.route_target', message: Acme\Command\RegisterUser }

The name of the tag is simple prooph_service_bus.<name-of-the-bus>.route_target. The additional message attribute defines the message name (message class by default) that is routed to the handler.

If your handler handles multiple messages, you need to add a tag for each one.

Automatic message detection

If you are not afraid of a little bit magic you can use automatic message detection to simplify the configuration and make it less vulnerable for refactoring. Instead of defining the message attribute add a message_detection attribute:

# app/config/services.yml
services:
    Acme\Command\RegisterUserHandler:
        tags:
            - { name: 'prooph_service_bus.acme_command_bus.route_target', message_detection: true }

The bundle will try to detect the message itself by analyzing the methods of the handler and creating instances of the message objects. But don't worry about performance because this will happen on compiling.

Important: Automatic message detection can only detect handlers where either the message implements Prooph\Common\Messaging\HasMessageName or the name of the method is __invoke. In both cases the object must be a non abstract class.

Hint: If you rely on automatic message detection and your handler handles multiple messages of the same message bus, you need to tag the handler just once.

Hint: Registering handlers can be extremely compact using the new DI features of Symfony 3.3:

services:
  _defaults:
    autowire: true
  
  App\Command\:
    resource: '../../src/Command/*Handler.php'
    tags: [{ name: 'prooph_service_bus.acme_command_bus.route_target', message_detection: true }]

Routing at the bus

If you are no fan of service tags, you can route the messages directly at the bus configuration:

# app/config/config.yml or (flex) config/packages/prooph_service_bus.yaml
prooph_service_bus:
    command_buses:
        acme_command_bus:
            router:
                routes:
                    'Acme\Command\RegisterUser': 'acme.command.register_user_handler'

This will work the same way for query buses.

When configuring event buses you can pass an array of service IDs for each event instead of a single service ID. This is necessary because events can be routed to multiple event handlers.

Hint: To get autocompletion in some IDEs you can prepend the service id with an @ ("@acme.command.register_user_handler").

The bundle will recognize this and find your handler anyway.

Which way you choose to configure your routing is up to you. Each way has its benefits and drawbacks.

Async switch

The async switch configuration allows to handle some messages asynchronously. For a general introduction into the AsyncSwitchMessageRouter please have a look at the official documentation.

In short: The AsyncSwitchMessageRouter decorates the configured router and sends messages that implement Prooph\ServiceBus\Async\AsyncMessage to a special message producer. Other messages will be handled by the decorated router.

To use this switch with symfony, configure your own message producer (it must implement Prooph\ServiceBus\Async\MessageProducer) and pass its service id to the configuration:

# app/config/config.yml or (flex) config/packages/prooph_service_bus.yaml
prooph_service_bus:
    command_buses:
        acme_command_bus:
            router:
                async_switch: 'my_async_message_producer'