Weave 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

Swarrot Bundle Laravel Package

swarrot/swarrot-bundle

SwarrotBundle integrates Swarrot message consumers into Symfony apps. Configure RabbitMQ connections, then define consumers with a processor service and a customizable middleware stack for signal handling, message limits, execution time, memory limits, and Doctrine integration.

View on GitHub
Deep Wiki
Context7

Getting Started

Know what it is first. SwarrotBundle is a thin Symfony DI/console layer over the core swarrot/swarrot library. The bundle gives you three things: a publisher service backed by named message_types, one console command per configured consumer, and a configurable middleware stack wrapped around your processor. It deliberately does not provision exchanges, queues or bindings — that is out of scope by design (the README points at odolbeau/rabbit-mq-admin-toolkit). If your team expects a bundle that also declares topology, this is not that bundle.

Requirements. As of 2.7.0 (2026-07-29): PHP >= 8.2 and Symfony 6.4 – 8.0. Older lines supported older Symfony, so pin deliberately.

composer require swarrot/swarrot-bundle

Register it the modern way — the README still shows app/AppKernel.php, which is stale:

// config/bundles.php
return [
    // ...
    Swarrot\SwarrotBundle\SwarrotBundle::class => ['all' => true],
];

Pick your provider up front. provider: pecl requires ext-amqp; provider: amqp_lib requires php-amqplib/php-amqplib. This is a one-line config choice, but it changes the whole transport stack underneath, so decide before you write consumers.

Minimal viable config — one connection, one consumer, one publishable type:

# config/packages/swarrot.yaml
swarrot:
    provider: amqp_lib
    default_connection: rabbitmq
    connections:
        rabbitmq:
            url: "%env(RABBITMQ_URL)%"
    consumers:
        order_consumer:
            processor: app.order_processor
            middleware_stack:
                - configurator: swarrot.processor.signal_handler
                - configurator: swarrot.processor.max_messages
                - configurator: swarrot.processor.exception_catcher
                - configurator: swarrot.processor.ack
            extras:
                poll_interval: 500000
    messages_types:
        order_publisher:
            connection: rabbitmq
            exchange: orders
            routing_key: order.created

First use case — publish from a controller/service, consume from a CLI worker:

$this->get('swarrot.publisher')->publish(
    'order_publisher',
    new \Swarrot\Broker\Message('{"id":42}')
);
bin/console swarrot:consume:order_consumer orders_queue rabbitmq

Where to look first when the README runs out: (1) the configuration reference block above — it is the de-facto reference for this bundle; (2) vendor/swarrot/swarrot/src/Swarrot/Processor/ for what each configurator service actually does and which extras keys it reads; (3) vendor/swarrot/swarrot-bundle/ for the *ProcessorConfigurator classes — they validate and translate your extras. With ~90 stars and effectively no dependents, the source is the documentation.

Implementation Patterns

Publisher with config overrides. message_types are reusable publish presets; override per call rather than duplicating entries:

$publisher->publish('order_publisher', $message, [
    'exchange'    => 'orders_dead',
    'routing_key' => 'order.failed',
    'connection'  => 'secondary',
]);

Inject swarrot.publisher (it is an explicitly public service) or add an alias in services.yaml for autowiring.

Processor = pure business logic. Implement Swarrot\Processor\ProcessorInterface::process(Message $message, array $options) and keep it free of broker concerns — acking, retrying, error catching and lifetimes belong in the middleware stack. This keeps processors unit-testable with a plain Message and an empty options array.

Compose the stack by intent, not by copy-paste. Read a consumer config as an ordered list of cross-cutting concerns, outermost first:

Position Typical configurator Why it sits there
outer signal_handler Must own the outermost loop to shut down gracefully between messages
max_messages / max_execution_time / memory_limit Process recycling for long-running workers
doctrine_connection, doctrine_object_manager Ping/reconnect and clear the EM between messages
exception_catcher Turns thrown exceptions into nacks instead of fatal errors
ack Commits the message after everything below it succeeded
inner retry Sees the raw exception first, republishes to the retry exchange
innermost your processor

Long-running workers. The pattern that works in production: signal_handler + max_messages + max_execution_time + doctrine_object_manager + services_resetter, run under Supervisor/systemd. services_resetter is the one people forget — it resets container services between messages so stateful services (mailers, request stacks, Doctrine) don't leak.

Retry with a dedicated exchange instead of requeueing on the same queue:

- configurator: swarrot.processor.retry
  extras:
      retry_exchange: retry
      retry_attempts: 3
      retry_routing_key_pattern: 'retry_%%attempt%%'

Provision the retry exchange and TTL/DLQ wiring outside the bundle.

One consumer per queue, many consumers per processor. Consumers are cheap; define several consumers reusing the same processor service but with different stacks (e.g. a fast one with max_messages: 100 and a bulk one with max_messages: 1) and give them human-friendly names via command_alias.

Custom middleware — implement ProcessorConfiguratorInterface, register it as abstract: true, reference the service id in middleware_stack. Same extension shape applies to providers: implement Broker\FactoryInterface, tag swarrot.provider_factory (optionally with alias: redis) and set swarrot.provider: redis.

Testing. Override the publisher class in the test env so publishes are no-ops:

# config/packages/test/swarrot.yaml
parameters:
    swarrot.publisher.class: Swarrot\SwarrotBundle\Broker\BlackholePublisher

For consumption tests, invoke swarrot:consume:<name> via CommandTester against a throwaway queue rather than trying to mock the internal loop.

Observability. Point swarrot.logger at a dedicated Monolog channel (monolog.logger.swarrot) so broker noise doesn't drown your app logs. Note the bundle ships a data collector, so the Symfony profiler shows publish activity in dev.

Gotchas and Tips

  • middleware_stack order is not cosmetic. Because each configurator decorates the next, the first entry is the outermost. Putting ack outside retry means a retried message is still acked; swapping them changes semantics entirely. Always reason about the stack outside-in.
  • CLI flags silently do nothing if the processor isn't in the stack. --no-catch, --no-retry, --max-messages, --max-execution-time only affect consumers that include the matching configurator. Easy hour to lose.
  • poll_interval is in microseconds (default 500000 ≈ 0.5 s), not milliseconds. --poll-interval on the command line overrides the config.
  • % must be escaped as %% in YAML, which is why the README writes retry_%%attempt%%. Single % gets parsed as a container parameter and blows up at compile time.
  • Queues are not in the config. Consumer commands take the queue name (and optional connection) as CLI arguments. That means queue naming lives in your deploy scripts, not your repository — keep it centralized or you will get drift between environments.
  • Doctrine state leaks between messages. If you write to entities in a processor without doctrine_object_manager, you accumulate a bloated identity map and stale entities. Pair it with doctrine_connection (doctrine_ping: true) when workers idle long enough for the broker to drop the connection.
  • Stale documentation is the norm here. Symfony < 5 patterns (AppKernel, processors_stack, publisher_logger) were removed in 2.0; blog posts and older StackOverflow answers will mislead you. Trust the changelog: 2.0 dropped processors_stack, 2.7.0 converted internal config files to PHP and added Symfony 8.
  • BlackholePublisher only silences publishing. It does not stub consumption, and overriding a container parameter is a blunt instrument — it also affects any code that reads swarrot.publisher.class. Prefer it in test only, or decorate the publisher service in a dedicated test container.
  • Publishing to a non-existent exchange fails at runtime, not at container build. Since the bundle refuses to manage topology, a missing exchange/queue surfaces as an AMQP error the first time you publish or consume. Add a boot-time health check if this bites you in staging.
  • Debugging toolkit: bin/console debug:container swarrot to see generated consumer commands and services; bin/console list swarrot to confirm command names (derived from consumer keys, so order_consumer → swarrot:consume:order_consumer); run with -vvv --no-catch to surface the real exception instead of a caught-and-logged one.
  • default_command is the escape hatch for anything the bundle won't let you configure — swap in a subclass of Swarrot\SwarrotBundle\Command\SwarrotCommand and extend the worker loop without forking the bundle.
  • Ecosystem risk is real: ~90 stars, zero dependents, no Flex recipe. Budget for reading vendor/ source, and pin the version — minor releases here have historically raised PHP/Symfony floors (2.5.0 → Symfony 7, 2.7.0 → PHP 8.2).
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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager