5.3 KiB
5.3 KiB
Queues & Background Jobs
This template includes Redis-powered queues for background processing.
Quick Start
# Start queue worker
make queue-start
# View queue logs
make queue-logs
# Stop queue worker
make queue-stop
# Restart after code changes
make queue-restart
Configuration
Queue is configured to use Redis in .env:
QUEUE_CONNECTION=redis
REDIS_HOST=redis
REDIS_PORT=6379
Creating Jobs
php artisan make:job ProcessOrder
<?php
namespace App\Jobs;
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ProcessOrder implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(
public Order $order
) {}
public function handle(): void
{
// Process the order
$this->order->update(['status' => 'processing']);
// Send notification, generate invoice, etc.
}
public function failed(\Throwable $exception): void
{
// Handle failure - log, notify admin, etc.
logger()->error('Order processing failed', [
'order_id' => $this->order->id,
'error' => $exception->getMessage(),
]);
}
}
Dispatching Jobs
// Dispatch immediately to queue
ProcessOrder::dispatch($order);
// Dispatch with delay
ProcessOrder::dispatch($order)->delay(now()->addMinutes(5));
// Dispatch to specific queue
ProcessOrder::dispatch($order)->onQueue('orders');
// Dispatch after response sent
ProcessOrder::dispatchAfterResponse($order);
// Chain jobs
Bus::chain([
new ProcessOrder($order),
new SendOrderConfirmation($order),
new NotifyWarehouse($order),
])->dispatch();
Job Queues
Use different queues for different priorities:
// High priority
ProcessPayment::dispatch($payment)->onQueue('high');
// Default
SendEmail::dispatch($email)->onQueue('default');
// Low priority
GenerateReport::dispatch($report)->onQueue('low');
Run workers for specific queues:
# Process high priority first
php artisan queue:work --queue=high,default,low
Scheduled Jobs
Add to app/Console/Kernel.php or routes/console.php:
// routes/console.php (Laravel 11+)
use Illuminate\Support\Facades\Schedule;
Schedule::job(new CleanupOldRecords)->daily();
Schedule::job(new SendDailyReport)->dailyAt('08:00');
Schedule::job(new ProcessPendingOrders)->everyFiveMinutes();
// With queue
Schedule::job(new GenerateBackup)->daily()->onQueue('backups');
Start scheduler:
make scheduler-start
Module Jobs
When creating module jobs, place them in the module's directory:
app/Modules/Inventory/
├── Jobs/
│ ├── SyncStock.php
│ └── GenerateInventoryReport.php
<?php
namespace App\Modules\Inventory\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class SyncStock implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 3;
public $backoff = [60, 300, 900]; // Retry after 1min, 5min, 15min
public function handle(): void
{
// Sync stock levels
}
}
Job Middleware
Rate limit jobs:
use Illuminate\Queue\Middleware\RateLimited;
use Illuminate\Queue\Middleware\WithoutOverlapping;
class ProcessOrder implements ShouldQueue
{
public function middleware(): array
{
return [
new RateLimited('orders'),
new WithoutOverlapping($this->order->id),
];
}
}
Monitoring
View Failed Jobs
php artisan queue:failed
Retry Failed Jobs
# Retry specific job
php artisan queue:retry <job-id>
# Retry all failed jobs
php artisan queue:retry all
Clear Failed Jobs
php artisan queue:flush
Production Setup
For production, use Supervisor instead of Docker:
# /etc/supervisor/conf.d/laravel-worker.conf
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/worker.log
stopwaitsecs=3600
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker:*
Testing Jobs
use Illuminate\Support\Facades\Queue;
it('dispatches order processing job', function () {
Queue::fake();
$order = Order::factory()->create();
// Trigger action that dispatches job
$order->markAsPaid();
Queue::assertPushed(ProcessOrder::class, function ($job) use ($order) {
return $job->order->id === $order->id;
});
});
it('processes order correctly', function () {
$order = Order::factory()->create(['status' => 'pending']);
// Run job synchronously
(new ProcessOrder($order))->handle();
expect($order->fresh()->status)->toBe('processing');
});