symfony/redis-messenger
Redis transport integration for Symfony Messenger, enabling queueing and async message handling backed by Redis. Part of the Symfony ecosystem, with links to contributing, issue reporting, and pull requests in the main Symfony repository.
Install the Package:
composer require symfony/redis-messenger
Ensure ext-redis is enabled in your PHP environment (PHP 8.1+ recommended).
Configure Redis Transport:
Add to your Laravel config/messenger.php (or Symfony config/packages/messenger.yaml if hybrid):
'transports' => [
'redis' => [
'dsn' => 'redis://127.0.0.1:6379',
'options' => [
'prefix' => 'messenger_', // Avoid key collisions
'read_write_timeout' => 2.0,
],
],
],
For Sentinel/Cluster (e.g., AWS ElastiCache):
'dsn' => 'redis+sentinel://user:pass@host1:26379,host2:26379/mydb?auth=pass&alias=master',
Dispatch a Message:
Create a Symfony Message class (e.g., app/Messages/ProcessOrder.php):
namespace App\Messages;
class ProcessOrder {
public function __construct(public string $orderId) {}
}
Dispatch via Laravel’s Bus facade (or Symfony’s MessageBus):
use Illuminate\Support\Facades\Bus;
Bus::dispatch(new ProcessOrder('order_123'));
Consume Messages:
Run the Symfony worker (replace redis with your transport name):
php bin/console messenger:consume redis -vv
Or integrate with Laravel’s queue system (see Implementation Patterns).
namespace App\Handlers;
use App\Messages\SendWelcomeEmail;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
#[AsMessageHandler]
class SendWelcomeEmailHandler {
public function __invoke(SendWelcomeEmail $message) {
Mail::to($message->email)->send(new WelcomeEmail($message->user));
}
}
Bus::dispatch(new SendWelcomeEmail($user->email, $user));
symfony/messenger + symfony/redis-messenger with Laravel’s Bus facade or a custom Queue adapter.Leverage Laravel’s Bus facade while using Symfony’s Redis transport:
// config/messenger.php
'transports' => [
'redis' => [
'dsn' => env('REDIS_DSN'),
'options' => [
'prefix' => 'laravel_messenger_',
],
],
],
// Dispatch via Laravel
Bus::dispatch(new ProcessPayment($orderId));
// Consume via Symfony CLI (or Laravel Artisan)
php artisan messenger:consume redis --limit=10
Pro Tip: Create a Laravel Queue adapter for Symfony’s MessageBus to reuse Laravel’s queue workers:
// app/Providers/AppServiceProvider.php
use Symfony\Component\Messenger\MessageBus;
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
public function register()
{
$this->app->singleton('symfony.message_bus', function ($app) {
$bus = new MessageBus([
new RedisTransport(
Redis::connection('default'),
new Serializer(),
'redis'
),
]);
return $bus;
});
}
Use Symfony’s routing keys to prioritize messages:
# config/packages/messenger.yaml
framework:
messenger:
transports:
redis:
dsn: '%env(REDIS_DSN)%'
options:
queues:
high: 'high_priority'
normal: 'normal_priority'
low: 'low_priority'
routing:
'App\Messages\ProcessOrder': high
'App\Messages\SendEmail': normal
'App\Messages\LogAnalytics': low
Laravel Integration:
// Dispatch to a specific queue
Bus::dispatch(new ProcessOrder($orderId))->setQueue('high');
Configure retries in config/messenger.php:
'failure_transport' => 'failed',
'failed_message_transport' => 'doctrine', // or 'redis' for dead-letter queue
'retries' => 3,
'retry_strategy' => [
'max_tries' => 3,
'delay' => 1000, // 1 second
'multiplier' => 2, // exponential backoff
'max_delay' => 0, // no max delay
],
Dead-Letter Queue (DLQ):
// config/messenger.php
'transports' => [
'failed' => [
'dsn' => 'redis://127.0.0.1:6379/1',
'options' => ['queue_name' => 'failed_messages'],
],
],
Run multiple workers for parallel processing:
# Terminal 1: High-priority queue
php artisan messenger:consume redis --queue=high --limit=5
# Terminal 2: Normal queue
php artisan messenger:consume redis --queue=normal --limit=10
# Terminal 3: Low-priority queue
php artisan messenger:consume redis --queue=low --limit=20
Dynamic Scaling: Use a process manager like Supervisor or Docker Compose to auto-scale workers based on queue depth.
Use Redis pub/sub for event-driven architectures:
// Publisher (e.g., after order processing)
Redis::connection()->publish('order_events', json_encode([
'event' => 'order.processed',
'order_id' => $orderId,
]));
// Subscriber (Symfony Messenger handler)
#[AsMessageHandler]
class OrderEventSubscriber {
public function __invoke(OrderEvent $event) {
// Broadcast to WebSocket clients, etc.
}
}
Laravel Integration: Pair with laravel-echo for real-time updates.
Unit Testing Handlers:
use Symfony\Component\Messenger\Test\MessageBusInterface;
public function testProcessOrder()
{
$bus = $this->createMock(MessageBusInterface::class);
$bus->expects($this->once())
->method('dispatch')
->with($this->isInstanceOf(ProcessOrder::class));
$handler = new ProcessOrderHandler($bus);
$handler(new ProcessOrder('order_123'));
}
Integration Testing:
Use Symfony’s TransportTestCase:
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
use Symfony\Component\Messenger\Transport\RedisExtTransport;
public function testRedisTransport()
{
$redis = Redis::connection();
$transport = new RedisExtTransport($redis, new Serializer(), 'test');
$this->assertTrue($transport->isStarted());
}
Duplicate Messages:
TransportMessageIdStamp (enabled by default) or implement idempotency in handlers.unique_id field to messages and track processed IDs in Redis:
Redis::connection()->sAdd('processed_messages', $message->getMessageId());
Connection Issues:
RedisException.redis-cli monitor).redis://user:pass@host:port/db).auth and alias are correctly configured.KeepaliveReceiverInterface:
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
use Symfony\Component\Messenger\Transport\RedisExtTransport;
$transport = new RedisExtTransport(
Redis::connection(),
new Serializer(),
'redis',
new KeepaliveReceiver()
);
Message Serialization:
How can I help you explore Laravel packages today?