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

Rabbit Bus Bundle Laravel Package

dimkabelkov/rabbit-bus-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install Dependencies

    composer require dimkabelkov/rabbit-bus-bundle
    composer require emag-tech-labs/rabbitmq-bundle  # Symfony 5
    # OR
    composer require php-amqplib/rabbitmq-bundle     # Symfony 4
    composer require symfony/monolog-bundle
    
  2. Configure Environment Add to .env for each service (e.g., APP_NAME=app-a):

    APP_NAME=app-a
    RABBITMQ_HOST=localhost
    RABBITMQ_USER=guest
    RABBITMQ_PASS=guest
    
  3. Define Shared Event Classes Create a shared package (e.g., you-app/bus-events) with events extending AbstractEvent:

    namespace App\Events\Shared;
    
    use Dimkabelkov\RabbitBusBundle\BusEvent\AbstractEvent;
    
    class OrderCreatedEvent extends AbstractEvent
    {
        public const EXCHANGE = 'app.order.created';
        public string $orderId;
    }
    
  4. Configure config/packages/rabbit_bus.yaml For a multi-consumer app (handles multiple event types):

    rabbit_bus:
        events:
            multiple: true
    

    For a single-consumer app (handles specific events):

    rabbit_bus:
        events:
            multiple: false
            consumers:
                - App\Events\Shared\OrderCreatedEvent
            producers:
                - App\Events\Shared\OrderCreatedEvent
    
  5. Enable Monolog Channel Add to config/packages/monolog.yaml:

    monolog:
        handlers:
            main:
                channels: ['%env(APP_NAME).rabbit-bus']
    
  6. Dispatch an Event In AppA:

    use App\Events\Shared\OrderCreatedEvent;
    
    $event = new OrderCreatedEvent();
    $event->orderId = '123';
    $this->bus->dispatch($event); // Auto-published to RabbitMQ
    
  7. Run the Consumer Start the consumer in a separate terminal:

    php bin/console rabbit-bus:consume
    

Implementation Patterns

Workflow: Event-Driven Microservices

  1. Producer Service (AppA)

    • Dispatches events to RabbitMQ for other services to consume.
    • Example: Order service emits OrderCreatedEvent after saving an order.
    $this->bus->dispatch(new OrderCreatedEvent($orderId));
    
  2. Consumer Service (AppB)

    • Subscribes to specific events (or all events if multiple: true).
    • Example: Inventory service listens for OrderCreatedEvent to update stock.
    # config/packages/rabbit_bus.yaml (AppB)
    rabbit_bus:
        events:
            multiple: false
            consumers:
                - App\Events\Shared\OrderCreatedEvent
    
  3. Shared Event Contracts

    • Define events in a shared package (e.g., you-app/bus-events) to ensure consistency across services.
    • Extend AbstractEvent and define EXCHANGE constants for routing.
  4. Error Handling

    • Use Monolog to log RabbitMQ errors:
    monolog:
        handlers:
            rabbit_bus:
                type: stream
                path: "%kernel.logs_dir%/%env(APP_NAME).rabbit-bus.log%"
                level: error
                channels: ['%env(APP_NAME).rabbit-bus']
    
  5. Testing

    • Mock the RabbitBus service in unit tests:
    $this->bus = $this->createMock(RabbitBus::class);
    $this->bus->expects($this->once())->method('dispatch');
    

Integration Tips

  1. Environment-Specific Configs Override rabbit_bus config per service using environment variables:

    # config/packages/rabbit_bus.yaml
    rabbit_bus:
        events:
            multiple: "%env(bool:RABBIT_BUS_MULTIPLE)%"
            consumers: "%env(var:RABBIT_BUS_CONSUMERS)%" # Comma-separated event classes
    
  2. Dynamic Routing Use event metadata (e.g., EXCHANGE) to route events to different queues:

    class OrderCancelledEvent extends AbstractEvent
    {
        public const EXCHANGE = 'app.order.cancelled';
    }
    
  3. Retry Logic Implement a dead-letter queue (DLQ) for failed messages by configuring RabbitMQ bindings:

    # rabbitmq-bundle config
    rabbitmq:
        connections:
            default:
                url: '%env(RABBITMQ_URL)%'
                lazy: true
                retry_strategy:
                    max_retries: 3
                    timeout: 1000
    
  4. Performance Tuning

    • Adjust prefetch count for consumers (default: 1):
    rabbit_bus:
        consumer_options:
            prefetch_count: 10
    
    • Use async consumers for high-throughput services.

Gotchas and Tips

Pitfalls

  1. Event Class Mismatch

    • Issue: Consumers fail silently if event classes don’t match exactly (including namespace).
    • Fix: Ensure all services use the same shared event package and validate classes in config:
    rabbit_bus:
        event_classes:
            - App\Events\Shared\OrderCreatedEvent
            - App\Events\Shared\OrderCancelledEvent
    
  2. Consumer Stuck in "Busy" State

    • Issue: Consumers may hang if messages aren’t processed quickly (e.g., slow DB operations).
    • Fix: Reduce prefetch_count or optimize consumer logic. Use ack()/nack() explicitly:
    public function handle(AbstractEvent $event): void
    {
        try {
            // Process event
            $this->bus->ack($event);
        } catch (\Exception $e) {
            $this->bus->nack($event);
            throw $e;
        }
    }
    
  3. Monolog Not Logging

    • Issue: RabbitMQ errors aren’t logged if the channel isn’t configured.
    • Fix: Verify APP_NAME.rabbit-bus is in Monolog’s channels list and the handler is active.
  4. Duplicate Messages

    • Issue: RabbitMQ may redeliver messages after consumer crashes.
    • Fix: Implement idempotency in consumers (e.g., check for existing records before processing).
  5. Configuration Overrides

    • Issue: Local overrides (e.g., config/packages/rabbit_bus_local.yaml) may not apply.
    • Fix: Use environment variables or merge configs explicitly:
    # config/packages/rabbit_bus.yaml
    rabbit_bus: *default
    

Debugging Tips

  1. Check Consumer Status Monitor active consumers via RabbitMQ management UI (http://localhost:15672) or CLI:

    rabbitmqctl list_consumers
    
  2. Enable Debug Logging Temporarily add a debug handler to Monolog:

    monolog:
        handlers:
            rabbit_bus_debug:
                type: stream
                path: "%kernel.logs_dir%/debug-rabbit-bus.log"
                level: debug
                channels: ['%env(APP_NAME).rabbit-bus']
    
  3. Validate Event Serialization Ensure events are serializable (avoid circular references or non-serializable properties). Use json_encode() to test:

    $event = new OrderCreatedEvent();
    json_encode($event); // Should not throw
    
  4. Test Locally with Docker Use a RabbitMQ container for isolation:

    # docker-compose.yml
    services:
        rabbitmq:
            image: rabbitmq:3-management
            ports:
                - "5672:5672"
                - "15672:15672"
    

Extension Points

  1. Custom Event Handlers Override the default handler resolution by binding your own:

    // src/RabbitBus/EventHandlerResolver.php
    namespace App\RabbitBus;
    
    use Dimkabelkov\RabbitBusBundle\BusEvent\AbstractEvent;
    use Dimkabelkov\RabbitBusBundle\EventHandlerResolverInterface;
    
    class CustomHandlerResolver implements EventHandlerResolverInterface
    {
        public function resolve(AbstractEvent $event): string
        {
            return 'App\\Handler\\' . class_basename($event) . 'Handler';
        }
    }
    

    Register in services:

    services:
        App\RabbitBus\CustomHandlerResolver:
            tags: [rabbit_bus.event_handler_resolver]
    
  2. Middleware for Events Add preprocessing/validation logic:

    use Dimkabelkov\RabbitBusBundle\Middleware\MiddlewareInterface;
    
    class
    
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.
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours