Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Messenger Bundle Laravel Package

coa/messenger-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation Add the bundle via Composer:

    composer require coa/messenger-bundle
    

    Register the bundle in config/bundles.php (Symfony 4+):

    return [
        // ...
        Coa\MessengerBundle\CoaMessengerBundle::class => ['all' => true],
    ];
    
  2. Basic Configuration Configure the bundle in config/packages/coa_messenger.yaml:

    coa_messenger:
        transports:
            async: '%env(MESSENGER_TRANSPORT_DSN)%'
        routing:
            'App\Message\YourMessage': async
    
  3. First Use Case Create a message class:

    namespace App\Message;
    
    class YourMessage
    {
        public function __construct(private string $content) {}
        public function getContent(): string { return $this->content; }
    }
    

    Dispatch the message in a controller/service:

    use Symfony\Component\Messenger\MessageBusInterface;
    
    class YourController
    {
        public function __construct(private MessageBusInterface $bus) {}
    
        public function handle()
        {
            $this->bus->dispatch(new YourMessage('Hello async world!'));
        }
    }
    
  4. Verify Setup Check the configured transport (e.g., Doctrine, Redis, or Symfony’s async transport) is running and processing messages.


Implementation Patterns

Core Workflows

  1. Message Dispatching

    • Use MessageBusInterface to dispatch messages:
      $this->bus->dispatch(new YourMessage($data));
      
    • For synchronous handling (e.g., during tests), inject Bus::class directly:
      $this->bus->dispatch(new YourMessage($data)); // Sync by default in tests
      
  2. Message Handling

    • Create handlers as services annotated with @AsMessageHandler:
      use Symfony\Component\Messenger\Attribute\AsMessageHandler;
      
      #[AsMessageHandler]
      class YourMessageHandler
      {
          public function __invoke(YourMessage $message)
          {
              // Process $message->getContent()
          }
      }
      
    • For complex logic, inject dependencies:
      #[AsMessageHandler]
      class YourMessageHandler
      {
          public function __construct(private LoggerInterface $logger) {}
      
          public function __invoke(YourMessage $message)
          {
              $this->logger->info('Processing:', ['content' => $message->getContent()]);
          }
      }
      
  3. Transport-Specific Patterns

    • Doctrine Transport: Use for persistence (e.g., retry failed messages):
      transports:
          doctrine: 'doctrine://default'
      
    • Redis Transport: For high-throughput async processing:
      transports:
          redis: 'redis://localhost'
      
    • Sync Transport: For testing or immediate execution:
      transports:
          sync: 'sync://'
      
  4. Middleware Integration

    • Add middleware to the bus (e.g., logging, validation):
      # config/packages/messenger.yaml
      framework:
          messenger:
              buses:
                  messenger.bus.default:
                      middleware:
                          - 'Coa\MessengerBundle\Middleware\YourMiddleware'
      
    • Create custom middleware:
      use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
      use Symfony\Component\Messenger\Middleware\StackInterface;
      
      class YourMiddleware implements MiddlewareInterface
      {
          public function handle($message, StackInterface $next)
          {
              // Pre-processing
              $result = $next($message);
              // Post-processing
              return $result;
          }
      }
      
  5. Retry Logic

    • Configure retry strategies in messenger.yaml:
      transports:
          async:
              dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
              retry_strategy:
                  max_retries: 3
                  delay: 1000
      

Integration Tips

  1. Laravel-Specific Adaptations

    • Use Laravel’s Bus facade for dispatching (if using Symfony Messenger as a drop-in):
      use Illuminate\Bus\Dispatcher;
      
      $dispatcher = app(Dispatcher::class);
      $dispatcher->dispatch(new YourMessage('Hello Laravel!'));
      
    • For Laravel’s queue system, bridge Symfony Messenger with queue:work:
      php artisan queue:work --queue=coa_messenger
      
  2. Event-Driven Architecture

    • Convert events to messages for async processing:
      // In an event listener
      $this->bus->dispatch(new ProcessUserEvent($user));
      
  3. Testing

    • Use Envelope for testing message flow:
      use Symfony\Component\Messenger\Envelope;
      use Symfony\Component\Messenger\MessageBusInterface;
      
      $envelope = new Envelope(new YourMessage('test'));
      $this->bus->dispatch($envelope);
      
    • Mock the bus in unit tests:
      $bus = $this->createMock(MessageBusInterface::class);
      $bus->expects($this->once())->method('dispatch');
      

Gotchas and Tips

Pitfalls

  1. Transport Configuration

    • Issue: Forgetting to configure the transport DSN (e.g., doctrine://default or redis://localhost).
    • Fix: Ensure MESSENGER_TRANSPORT_DSN is set in .env and matches the bundle’s expectations.
    • Debug: Check php bin/console messenger:consume async -vv for connection errors.
  2. Handler Registration

    • Issue: Handlers not autowired if missing @AsMessageHandler or not tagged as services.
    • Fix: Explicitly tag handlers in services.yaml:
      services:
          App\MessageHandler\YourMessageHandler:
              tags: ['messenger.message_handler']
      
  3. Message Serialization

    • Issue: Non-serializable messages (e.g., closures, resources) failing silently.
    • Fix: Use #[AsMessage] attribute or implement Serializable:
      use Symfony\Component\Messenger\Attribute\AsMessage;
      
      #[AsMessage]
      class YourMessage implements Serializable
      {
          // ...
      }
      
  4. Middleware Order

    • Issue: Middleware not executing in expected order (e.g., validation failing before logging).
    • Fix: Define middleware order explicitly in messenger.yaml:
      middleware:
          - 'Coa\MessengerBundle\Middleware\Validate'
          - 'Coa\MessengerBundle\Middleware\Log'
      
  5. Laravel Queue Conflicts

    • Issue: Symfony Messenger and Laravel Queues competing for the same DB table (e.g., jobs).
    • Fix: Use separate tables or transports (e.g., Redis for Messenger, DB for Laravel Queues).

Debugging Tips

  1. Consume Messages Manually Run the consumer to inspect messages:

    php bin/console messenger:consume async --time-limit=3600
    
  2. Check Failed Messages List failed messages:

    php bin/console messenger:failed:list
    

    Retry a failed message:

    php bin/console messenger:failed:retry <message-id>
    
  3. Log Middleware Execution Add debug logging to middleware:

    use Psr\Log\LoggerInterface;
    
    class DebugMiddleware implements MiddlewareInterface
    {
        public function __construct(private LoggerInterface $logger) {}
    
        public function handle($message, StackInterface $next)
        {
            $this->logger->debug('Handling message:', ['class' => get_class($message)]);
            return $next($message);
        }
    }
    
  4. Environment-Specific Config Override transport settings per environment:

    # config/packages/coa_messenger/dev.yaml
    coa_messenger:
        transports:
            async: 'sync://' # Use sync in dev
    

Extension Points

  1. Custom Transports Extend Coa\MessengerBundle\Transport\AbstractTransport to create new transports (e.g., for Kafka or RabbitMQ).

  2. Dynamic Routing Use a RouterInterface to dynamically route messages:

    use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
    use Symfony\Component\Messenger\Transport\TransportInterface;
    
    class DynamicRouter implements RouterInterface
    {
        public function getRoute(Envelope $envelope): ?TransportInterface
        {
            if ($envelope->getMessage() instanceof YourMessage) {
                return new Transport('async://');
            }
            return null;
        }
    }
    
  3. Message Metadata Attach metadata to messages for tracking:

    $envelope = new Envelope(new YourMessage('test'), [
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware