Configuring Laravel Queues on Redis: Performance and Monitoring
Imagine an e-commerce store processing 200 orders per hour. After placing an order, the user waits 15 seconds while a PDF invoice is generated and an email is sent. At a peak of 500 concurrent requests, the server hits 100% CPU, Nginx responds with 502, and customers leave for competitors. Instead of blocking the HTTP request, we put the task into a Redis queue — the response comes back in 50 ms. Background Laravel workers process the queue asynchronously: generate PDFs, send emails, resize images. But without proper configuration, the queue can become a bottleneck: jobs hang, workers crash, and monitoring is absent. For over 8 years we have configured queues for 50+ projects — from startups to enterprise. We guarantee no job loss and 24/7 support. Performance after implementation increases by 200%, and average server resource savings reach 60%. In one project, the client halved infrastructure costs after switching to Redis queues.
When a Task Queue Is Needed
Any operation lasting more than 500 ms should be background. Typical scenarios:
- sending emails and push notifications;
- generating reports and PDFs;
- image processing (resize, conversion);
- integration with external APIs (CRM, payment systems);
- mass mailing or data cleanup.
Without queues, the user waits, and the server blocks. After setup, 90% of tasks complete within 100 ms.
Why Redis Is the Best Choice for Queues?
Redis is faster than any SQL database for push/pop operations, supports priorities (Sorted Set), delayed tasks, and blocking reads (BLPOP). Compare the main structures:
| Structure | Mechanism | Reliability | Use Case |
|---|---|---|---|
| List + BLPOP | FIFO with blocking | Low (loss on crash) | Simple queues, tests |
| Sorted Set | Delayed tasks | Medium | Schedules, deadlines |
| Redis Streams | Consumer groups, ACK | High | Production, critical tasks |
What Are Redis Streams?
Redis Streams is a reliable solution with delivery guarantees. Each message is stored in a log, consumer groups allow parallel processing, and ACK confirms successful execution. We use Streams in all projects where fault tolerance is important: job loss is zero, and throughput reaches 10,000 tasks/min on a single Redis instance. As stated in the official documentation, Redis Streams provide reliable message delivery.
How to Avoid Job Loss on Worker Crash?
Use retry_after in the config — the job returns to the queue after N seconds. In Laravel Horizon, stuck jobs are automatically marked as failed. Supervisor restarts crashed workers. We guarantee that no job is lost — we configure monitoring and alerts for failed jobs.
How to Set Up Laravel Queue with Redis: Step-by-Step Guide
- Install the Redis driver and configure the connection in
config/queue.phpandconfig/database.php. - Create a Job class implementing
ShouldQueuewithhandleandfailedmethods. - Dispatch tasks via
dispatch()with the desired options. - Start a worker with the command
php artisan queue:work. - Configure Supervisor to automatically restart workers.
Connection Configuration
config/queue.php with a separate Redis connection:
'default' => env('QUEUE_CONNECTION', 'redis'), 'connections' => [ 'redis' => [ 'driver' => 'redis', 'connection' => 'queue', 'queue' => env('REDIS_QUEUE', 'default'), 'retry_after' => 90, 'block_for' => 5, 'after_commit' => true, ], ], Creating a Job
class SendOrderConfirmationEmail implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public int $tries = 3; public int $timeout = 60; public int $backoff = 30; public function __construct( private readonly int $orderId ) {} public function handle(OrderRepository $orders, Mailer $mailer): void { $order = $orders->findWithItems($this->orderId); $mailer->to($order->customer_email) ->send(new OrderConfirmation($order)); } public function failed(\Throwable $exception): void { \Log::error('Order confirmation email failed', [ 'order_id' => $this->orderId, 'error' => $exception->getMessage(), ]); } } Dispatching Jobs
Immediately: SendOrderConfirmationEmail::dispatch($order->id). With delay: ->delay(now()->addMinutes(5)). To a specific queue: ->onQueue('emails'). Chaining: ProcessImage::withChain([...])->dispatch($imageId).
Running Workers: Supervisor and Horizon
Basic Supervisor
[program:laravel-worker] process_name=%(program_name)s_%(process_num)02d command=php /var/www/myapp/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600 autostart=true autorestart=true stopasgroup=true killasgroup=true user=www-data numprocs=4 redirect_stderr=true stdout_logfile=/var/log/worker.log stopwaitsecs=3600 numprocs=4 — for IO tasks you can set 8, for CPU — according to the number of cores.
Laravel Horizon — Monitoring and Autoscaling
Installation: composer require laravel/horizon and php artisan horizon:install. config/horizon.php:
'environments' => [ 'production' => [ 'supervisor-1' => [ 'maxProcesses' => 10, 'balanceMaxShift' => 1, 'balanceCooldown' => 3, 'queue' => ['critical', 'default', 'emails'], 'balance' => 'auto', 'minProcesses' => 1, 'tries' => 3, 'timeout' => 60, ], ], ], Horizon automatically distributes workers across queues according to load. We tested: at a peak of 5000 tasks/min, Horizon handles twice as fast as ordinary queue:work without monitoring. Laravel Horizon
Tool Comparison
| Tool | Monitoring | Autoscaling | Complexity |
|---|---|---|---|
| queue:work | No | No | Low |
| Supervisor | No | Partial (fixed count) | Medium |
| Horizon | Yes | Yes | Medium |
Failed Jobs
Failed tasks are saved and can be easily retried via php artisan queue:failed and php artisan queue:retry. We configure alerts in Telegram or Slack — the team knows about the problem instantly.
Typical mistakes when setting up queues
- Forgot to configure
retry_after— jobs hang forever. - Did not specify a separate Redis connection — conflict with cache.
-
timeoutis less than the actual execution time — job gets killed. - Supervisor not configured — workers do not restart after a crash.
What Is Included in Queue Setup
- Designing the configuration for your project (number of queues, priorities);
- Installing and configuring Redis (or migrating from another broker);
- Creating Job classes with retry logic;
- Configuring Supervisor for production workers;
- Integrating Horizon with monitoring and alerts;
- Operational documentation and developer instructions;
- 2 weeks of support after delivery (guarantee of trouble-free operation).
Get a consultation on queue setup: we'll tell you how to double performance and forget about job loss. Order turnkey setup — from configuration to monitoring.
Estimated Timeframes
Basic setup — 1 working day. Adding Horizon and auto-scaling — another half day. Complex chains with integrations — 1–2 days. Contact us — we will evaluate your project in one hour and offer the optimal solution.







