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

Laravel Rabbitmq Laravel Package

kunalvarma05/laravel-rabbitmq

Laravel RabbitMQ integration package for publishing and consuming messages with configurable connections, queues, and exchanges. Provides a simple Laravel-friendly API and artisan commands for working with RabbitMQ in your applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and wire up

composer require kunalvarma05/laravel-rabbitmq
php artisan vendor:publish --provider="KunalVarma05\RabbitMQ\RabbitMQServiceProvider"

On Laravel 5.5+ the provider/facade are auto-discovered. On older versions register KunalVarma05\RabbitMQ\RabbitMQServiceProvider in config/app.php and alias the facade ('RabbitMQ' => KunalVarma05\RabbitMQ\Facades\RabbitMQ::class).

The published config/rabbitmq.php is the first file to read. It holds host, port, username, password, and vhost, almost always fed from .env:

RABBITMQ_HOST=127.0.0.1
RABBITMQ_PORT=5672
RABBITMQ_USERNAME=guest
RABBITMQ_PASSWORD=guest
RABBITMQ_VHOST=/

Where to look first

  1. config/rabbitmq.php — connection settings and any default queue/exchange names.
  2. src/RabbitMQ.php and src/Facades/RabbitMQ.php — the public surface. The facade proxies a single manager class; read its method signatures before writing anything, because the package is thin and you will spend most of your time one layer down in php-amqplib.
  3. src/Connection.php / src/Channel.php (or equivalent) — the wrapper objects that expose queue(), exchange(), publish(), consume(), close(). This is where the actual AMQP calls happen.

First use case: publish to a queue and drain it

use KunalVarma05\RabbitMQ\Facades\RabbitMQ;

// Producer: declare (idempotent) then publish
$channel = RabbitMQ::connection()->channel();
$channel->queue('orders.created', /* durable */ true);
$channel->publish(json_encode(['id' => 42]), 'orders.created');

Then confirm it landed before writing the consumer:

rabbitmqctl list_queues name messages_ready messages_unacknowledged
# or open the management UI at http://localhost:15672

A one-shot consumer that proves the read path:

$channel->consume('orders.created', function ($message) {
    logger($message->body);
    $message->ack(); // if the package doesn't auto-ack
});

Once publish → queue → consume works end to end, wrap the consumer in an Artisan command (see next section) rather than leaving it in a route or tinker session.


Implementation Patterns

Wrap the facade in your own service

The facade is a global, stateless-looking entry point, but it holds a live TCP connection. Don't call it from controllers. Bind one thin service in the container and inject it:

namespace App\Messaging;

use KunalVarma05\RabbitMQ\Facades\RabbitMQ;

class Publisher
{
    public function publish(string $routingKey, array $payload, string $exchange = ''): void
    {
        $channel = RabbitMQ::connection()->channel();
        $channel->publish(
            json_encode($payload + ['published_at' => now()->toIso8601String()]),
            $routingKey,
            $exchange
        );
    }
}

This gives you one place to add correlation IDs, retries, and headers, and one place to fake in tests.

Consumer as an Artisan command, run under Supervisor

The package blocks inside consume(), so the consumer belongs in a long-lived command, not a job:

class ConsumeOrders extends Command
{
    protected $signature = 'rabbit:consume-orders';
    protected $description = 'Drain the orders.created queue';

    public function handle(): int
    {
        $channel = RabbitMQ::connection()->channel();
        $channel->queue('orders.created', true);
        $channel->qos(0, 10); // prefetch — do this *before* consume

        $channel->consume('orders.created', function ($message) {
            try {
                ProcessOrder::dispatchSync(json_decode($message->body, true));
                $message->ack();
            } catch (\Throwable $e) {
                report($e);
                $message->nack(false); // requeue=false -> route to DLX or drop
            }
        });

        return self::SUCCESS;
    }
}

Run it with:

[program:rabbit-orders]
command=php /var/www/artisan rabbit:consume-orders
numprocs=2
autostart=true
autorestart=true
stopwaitsecs=30

Exchanges for fan-out, queues for work

Use a named exchange with a routing key when more than one consumer needs the same event; publish directly to a queue only for pure work-queue semantics. Declare exchanges and bindings explicitly at boot (a deploy script or a rabbit:declare command) so that a consumer can never race a missing binding and silently drop messages.

Envelope your payloads

The package moves strings; it does not impose a schema. Always ship JSON with a stable shape:

['event' => 'order.created', 'version' => 1, 'data' => [...], 'id' => (string) Str::uuid()]

The id doubles as your idempotency key — RabbitMQ is at-least-once, and a redelivered message after a nack(requeue: true) is normal, not exceptional.

Bridge Laravel events to RabbitMQ

For domain events you want other services to hear, register a listener that forwards to your Publisher. Keep the Laravel event synchronous and the AMQP publish inside it only if you can tolerate the latency; otherwise wrap it in dispatchAfterResponse() or a queued listener so a broker outage doesn't fail the HTTP request.

Testing

Because everything funnels through the facade, RabbitMQ::shouldReceive('connection') is enough to unit-test producers — but it's brittle. Prefer swapping your own Publisher interface in the container with a fake that records messages:

$this->mock(Publisher::class, fn ($m) => $m->shouldReceive('publish')->once());

Never point the test suite at a real broker; the package has no in-memory driver.


Gotchas and Tips

This is not a Laravel queue driver. It does not plug into queue:work, Horizon, or ShouldQueue. If you want RabbitMQ as the backend for Laravel's queue system, you need vladimir-yuldashev/laravel-queue-rabbitmq, not this. Confusing the two is the most common mistake made with this package.

Long-running consumers leak. php-amqplib keeps the socket, channel, and message frames in memory. In a consume() loop:

  • call DB::reconnect() periodically, or your MySQL connection will time out and throw mid-message;
  • cap the worker (--max-messages in your own command) and let Supervisor restart it;
  • if you see RSS climbing, the culprit is usually large message bodies retained by your own closure, not the library.

No built-in reconnect. If the broker restarts, consume() throws AMQPConnectionClosedException and the process exits. Either wrap the call in a retry loop with backoff, or rely on Supervisor's autorestart=true. Heartbeats (default 60s) only help if your handler isn't blocking long enough to miss them — long handlers need pcntl_alarm or a shorter prefetch.

basic_qos must be called before consume. Setting prefetch after the consume call has no effect. If you see a single worker eating the entire queue while others idle, this is why.

Ack discipline. If the package does not auto-ack in your usage, a forgotten $message->ack() leaves messages in unacknowledged forever, and they only come back when the channel closes. Watch messages_unacknowledged in rabbitmqctl list_queues — non-zero and static means a hung consumer.

Redeclaration mismatches are fatal. Declaring a queue with durable=false in dev and durable=true in prod against the same broker gives PRECONDITION_FAILED - inequivalent arg. Pick your flags once, put them in config, and use the same values everywhere. Delete and recreate the queue in dev rather than tweaking the declaration.

config:cache freezes env. After php artisan config:cache, env('RABBITMQ_HOST') inside a consumer returns null because env() only reads the real environment. The package config should call env() itself (it does), but never call env() from your own consumer code — use config('rabbitmq.host').

vhost / is a slash. It's fine in the config array, but if you ever hand-build a connection URI (e.g. for the management API or rabbitmqadmin), / must be percent-encoded as %2F.

No publisher confirms by default. publish() returning without an exception does not mean the broker persisted the message. If you need durability guarantees, enable confirms on the channel and wait_for_pending_acks(), or accept fire-and-forget semantics and design consumers to be idempotent instead.

Message size. The default frame_max is 131072 bytes. Large payloads get split across frames and can trip consumers; keep messages under a few hundred KB and put blobs in S3 with a pointer in the body.

Debugging. The management plugin is worth the two minutes it takes to enable — you can inspect queues, purge them, publish a test message into your consumer, and read the exact PRECONDITION_FAILED text instead of guessing. For CLI, rabbitmqctl list_bindings and rabbitmqctl list_consumers answer "why is nothing arriving" faster than any log.

Version pinning and upkeep. The package is small, low-traffic, and lightly maintained. Read composer.json before adopting: check the php-amqplib constraint against your PHP version (PHP 8.1+ support in older tags is spotty), pin an exact version, and be prepared to fork. If you only need publish/consume, dropping to php-amqplib directly is a couple hundred lines and removes the maintenance risk entirely.

Extension points. The service provider binds a singleton connection from config/rabbitmq.php; you can rebind it in a AppServiceProvider::register() to point at multiple brokers (one container key per connection) if you need more than one vhost or cluster. There is no formal extension API beyond that — the wrapper classes are concrete, so subclassing is your only hook.

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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator