danielkorytek/messenger-bridge-bundle

Messenger bridge for Docplanner messaging standard

Installs: 16 328

Dependents: 0

Suggesters: 0

Security: 0

Stars: 1

Watchers: 3

Forks: 1

Open Issues: 0

Type:symfony-bundle

0.6.1 2022-01-17 18:05 UTC

This package is auto-updated.

Last update: 2024-04-17 22:50:01 UTC


README

Routing key middleware

That middleware gives an ability to routing key modification ie: add current locale key to current message key.

RoutingKeyMiddleware is implementing RoutingKeyResolverInterface.

Configuration:

  • Register middleware
messenger.bridge.routing.app_id_routing_key_resolver:
   class: DanielKorytek\MessengerBridgeBundle\Message\Routing\RoutingKeyResolver\AppIdRoutingKeyResolver

Symfony < 5.1
messenger.bridge.middleware.routing_key:
   class: DanielKorytek\MessengerBridgeBundle\Middleware\RoutingKeyMiddleware
   arguments:
     - '@messenger.bridge.routing.app_id_routing_key_resolver'
   tags:
     - { name: messenger.middleware }

Symfony >= 5.1

messenger.bridge.middleware.routing_key:
   class: DanielKorytek\MessengerBridgeBundle\Middleware\Symf51\RoutingKeyMiddleware
   arguments:
     - '@messenger.bridge.routing.app_id_routing_key_resolver'
   tags:
     - { name: messenger.middleware }
  • Attach a middleware to messenger

In messenger.yml put messenger.bridge.middleware.routing_key to your bus middleware list.

Example:

framework:
       messenger:
           default_bus: command.bus
           buses:
               command.bus: ~
               shared.message.bus:
                   default_middleware: allow_no_handlers
                   middleware:
                       - messenger.bridge.middleware.routing_key

Serialization

For serialize/deserialize messages package is using symfony/serializer. To endure adequate possibility for serialization/deserialization process, you need enable normalizers and denormalizers.

Required serializer configuration:

services:
    serializer.property.normalizer:
        class: Symfony\Component\Serializer\Normalizer\PropertyNormalizer
        arguments:
            - '@serializer.mapping.class_metadata_factory'
            - '@serializer.name_converter.metadata_aware'
            - '@property_info'
            - '@serializer.mapping.class_discriminator_resolver'
            - null
            - []
        tags:
            - { name: serializer.normalizer }

    serializer.date_time.normalizer:
        class: Symfony\Component\Serializer\Normalizer\DateTimeNormalizer
        tags:
            - { name: serializer.normalizer }

    serializer.array_denormalizer:
        class: Symfony\Component\Serializer\Normalizer\ArrayDenormalizer
        tags:
            - { name: serializer.denormalizer }

Bus example configuration

framework:
    messenger:
        #your other buses here
        buses:
            shared.message.bus:
                default_middleware: allow_no_handlers
                middleware:
                    #here other middlewares like doctorine transaction etc.
                    - messenger.bridge.middleware.routing_key
        #here is global bus serializer configuration
        serializer:
            default_serializer: messenger.transport.symfony_serializer
            symfony_serializer:
                format: json
                context: { }
        #here is transport configuration
        transports:
            #other transports here
            shared: #configuration of outgoing exchange (messenger is publishing messages here to other apps)
                serializer: messenger.bridge.serializer #our custom serializer for correct serialization/deserialization shared event messages 
                dsn: "%env(MESSENGER_TRANSPORT_DSN)%" #dsn to rabbitmq
                options:
                    exchange:
                    name: "%env(MESSENGER_SHARED_EXCHANGE_NAME)%" #outgoing exchange name 
                    type: topic
            
            incoming:
                 serializer: messenger.bridge.serializer
                 dsn: "%env(MESSENGER_TRANSPORT_DSN)%"
                 options:
                    queues:
                        incoming_events: #your queue name (here yours app receives messages from other apps via exchange)
                            binding_keys:
                                - "%locale%.app-name.smth.changed" #routing key binding list
                    exchange:
                        name: "%env(MESSENGER_SHARED_INCOMING_EXCHANGE_NAME)%" #incoming exchange name
                        type: topic

Messages

All messages representation classes HAVE TO implement NamedMessageInterface. Every message handled by bus, without implementing NamedMessageInterface will throws UnsupportedMessage exception.

Publishing

  1. Check if your bus has allow_no_handlers middleware (it's required). Your bus will publish message to transport only when you don't have any subscriber class for that message.
  2. Add your message FQCN to messenger routing configuration with correct transport name:
       routing:
                'App\SharedEventBus\Test': shared
    

Subscribing

  • Register serializer for external messages
services:

  messenger.bridge.bus_stamp_docplanner.serializer:
    class: DanielKorytek\MessengerBridgeBundle\Message\Serializer\BusStampEnvelopeSerializer
    arguments:
      - '@messenger.bridge.serializer' #docplanner SEB  messages serializer
      - 'shared.message.bus' #bus name from messenger configuration
  • Add message binding key in your incoming transport: This step is for messenger command. If you're using different package, you should update config in proper place.
 incoming:
    serializer: messenger.bridge.bus_stamp_docplanner.serializer 
    dsn: "%env(MESSENGER_TRANSPORT_DSN)%"
    options:
        queues:
            incoming_events: #your queue name (here yours app receives messages from other apps via exchange)
                binding_keys:
                    - "%locale%.app-name.smth.changed"
                    - "%locale%.app-name.smth"  #new key
        exchange:
            name: "%env(MESSENGER_SHARED_INCOMING_EXCHANGE_NAME)%" #incoming exchange name
            type: topic
service:
   messenger.bridge.bus_stamp_docplanner.serializer:
        class: DanielKorytek\MessengerBridgeBundle\Message\Serializer\BusStampEnvelopeSerializer
        arguments:
            - '@messenger.bridge.serializer'
            - 'bus.name.from.messenger.configuration'
  • Create representation class for a message.
  • Attach message mapping to messenger.bridge.subscriber_events_mapping parameter:
messenger.bridge.subscriber_events_mapping:
    app-name.smth.changed: App\Namespace\MessageClass
  • Create subscriber class and bind with correct bus:
<?php

declare(strict_types=1);

namespace App\SharedEventBus;


use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;

class SaasAttendanceSubscriber implements MessageSubscriberInterface
{
    public function __invoke(MessageClass $messageClass): Envelope
    {
        return new Envelope($messageClass);
    }

    public static function getHandledMessages(): iterable
    {
        yield MessageClass::class => [
            'bus' => 'shared.message.bus',
        ];
    }

}