Skip to content
SpoolrailSpoolrail

Spoolrail

Laravel-native message brokering for distributed systems, with one API across RabbitMQ, AWS SNS/SQS, and Google Pub/Sub.

Spoolrail lets Laravel applications exchange messages through a broker.

Message brokers let different apps communicate without being directly connected. One app sends a message, the broker holds it, and another app picks it up later. Think of it like leaving a note for your coworker instead of waiting around to tell them in person.

This prevents the brittleness of direct HTTP calls, where one app has to wait for the other. So, whether the receiving app is offline or the system is overwhelmed by a sudden spike in traffic, messages wait safely for each subscription until its application is ready to process them.

Message brokers are common in microservices and service-oriented architectures to handle async communication and keep things loosely coupled.

Publishing applications send messages to topics. Spoolrail uses fanout delivery so every application subscribed to a topic gets its own copy. Spoolrail hands each copy to the Laravel queue selected by the receiving application’s subscription.

This handoff separates broker delivery from handler execution. After Laravel queue accepts the message, it owns handler execution, retries, and failure.

By default, Spoolrail delivers every published message once and in order to each subscription’s Laravel queue. This guarantee covers ordinary publication and broker redeliveries.

Some drivers let you disable one or more guarantees to raise the throughput limit. Read more about delivery guarantees.

Message broker systems are powerful, but that power can lead to complexity. There are no plans to chase every feature or configuration knob across drivers with this package.

The goal is to focus on what’s essential for every broker implementation, delivering an elegant, driver-agnostic, and delightful API — even if that means leaving some bells and whistles behind.

Terminal window
composer require spoolrail/spoolrail
Terminal window
php artisan spoolrail:install

The installer publishes config/spoolrail.php and creates routes/subscriptions.php.

Set a stable ownership prefix for the app in .env. The ownership prefix distinguishes this application’s subscriptions from subscriptions owned by other applications:

SPOOLRAIL_PREFIX=warehouse

Choose a driver below.

Install the RabbitMQ client:

Terminal window
composer require php-amqplib/php-amqplib:^3.7.4

Select the RabbitMQ connection and configure the broker in .env:

SPOOLRAIL_CONNECTION=rabbitmq
RABBITMQ_HOST=127.0.0.1
RABBITMQ_USERNAME=spoolrail
RABBITMQ_PASSWORD=secret
RABBITMQ_VHOST=spoolrail
RABBITMQ_MANAGEMENT_URL=http://127.0.0.1:15672

This walkthrough requires RabbitMQ 4.3 or later with the Management plugin enabled. See the RabbitMQ driver guide for TLS and other connection settings.

You can use make:handler to scaffold the class:

<?php
namespace App\Messages;
use App\Services\Inventory;
use Spoolrail\Spoolrail\Contracts\MessageHandler;
use Spoolrail\Spoolrail\Message;
class ReserveInventoryHandler implements MessageHandler
{
public function __construct(
private readonly Inventory $inventory,
) {}
public function handle(Message $message): void
{
$this->inventory->reserve(
(int) $message->payload['order_id'],
);
}
}

Add the subscription to routes/subscriptions.php:

<?php
use App\Messages\ReserveInventoryHandler;
use Spoolrail\Spoolrail\Facades\Spoolrail;
Spoolrail::subscribe(
topic: 'orders',
name: 'warehouse-orders',
handler: ReserveInventoryHandler::class,
);

Spoolrail loads this file automatically.

Terminal window
php artisan spoolrail:ensure-topology

Run this command during deployment whenever subscription declarations change.

Run consumers for every subscription on the default Spoolrail connection:

Terminal window
php artisan spoolrail

Make sure Laravel queue workers are running for the connections and queues selected by your subscriptions.

use Spoolrail\Spoolrail\Facades\Spoolrail;
use Spoolrail\Spoolrail\Message;
$published = Spoolrail::publish(
'orders',
Message::make('order.created', [
'order_id' => $order->id,
]),
);

The returned message contains the UUID and UTC publication time that subscribers receive.