Laravel

Queues & Jobs

Laravel queues allow you to defer time-consuming tasks (emails, notifications, file processing) to background workers, keeping your app fast and responsive.

Queue Driver Config: Set the queue connection in your .env file. Common drivers: sync (immediate, no worker needed), database, redis, sqs.
📄.env
ENV
QUEUE_CONNECTION=database

# For Redis driver
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
Create Jobs Table: When using the database driver, run these commands to create the jobs and failed_jobs tables.
📄terminal
BASH
php artisan queue:table
php artisan queue:failed-table
php artisan migrate
Creating a Job Class: Use make:job Artisan command. The handle() method contains the logic that runs in the background.
📄terminal
BASH
php artisan make:job SendWelcomeEmail
📄app/Jobs/SendWelcomeEmail.php
PHP
<?php

namespace App\Jobs;

use App\Models\User;
use App\Mail\WelcomeMail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;

class SendWelcomeEmail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $tries = 3;        // Retry up to 3 times on failure
    public int $timeout = 60;     // Max seconds to run

    public function __construct(public User $user) {}

    public function handle(): void
    {
        Mail::to($this->user->email)
            ->send(new WelcomeMail($this->user));
    }

    public function failed(\Throwable $exception): void
    {
        // Called when all retry attempts are exhausted
        logger()->error("SendWelcomeEmail failed for user {$this->user->id}: " . $exception->getMessage());
    }
}
Dispatching a Job: Use the dispatch() helper or the static ::dispatch() method from within a controller or service.
📄app/Http/Controllers/RegisterController.php
PHP
use App\Jobs\SendWelcomeEmail;

public function store(Request $request): RedirectResponse
{
    $user = User::create($request->validated());

    // Dispatch immediately to queue
    SendWelcomeEmail::dispatch($user);

    // Or using the helper
    dispatch(new SendWelcomeEmail($user));

    // Dispatch only if a condition is true
    SendWelcomeEmail::dispatchIf($user->email_verified_at === null, $user);

    return redirect()->route('dashboard');
}
Delay & Chaining: You can delay job execution or chain multiple jobs to run sequentially after one another.
📄app/Http/Controllers/OrderController.php
PHP
use App\Jobs\ProcessPayment;
use App\Jobs\SendOrderConfirmation;
use App\Jobs\UpdateInventory;

// Delay job by 10 minutes
SendWelcomeEmail::dispatch($user)->delay(now()->addMinutes(10));

// Chain jobs — each runs after the previous succeeds
ProcessPayment::withChain([
    new SendOrderConfirmation($order),
    new UpdateInventory($order),
])->dispatch($order);

// Using Bus facade for chaining
use Illuminate\Support\Facades\Bus;

Bus::chain([
    new ProcessPayment($order),
    new SendOrderConfirmation($order),
    new UpdateInventory($order),
])->dispatch();

// Dispatch on a specific queue name
SendWelcomeEmail::dispatch($user)->onQueue('emails');
Failed Jobs: Failed jobs are stored in the failed_jobs table. Use Artisan commands to inspect and retry them.
📄terminal – failed jobs management
BASH
# List all failed jobs
php artisan queue:failed

# Retry a specific failed job by ID
php artisan queue:retry 1

# Retry all failed jobs
php artisan queue:retry all

# Delete a specific failed job
php artisan queue:forget 1

# Flush (delete) all failed jobs
php artisan queue:flush
Running the Queue Worker: The worker processes jobs from the queue. Use --queue to specify priority queues and --tries to limit retries.
📄terminal – queue worker
BASH
# Start the queue worker (processes jobs continuously)
php artisan queue:work

# Process from a specific connection and queue
php artisan queue:work redis --queue=high,emails,default

# Set max tries and timeout
php artisan queue:work --tries=3 --timeout=90

# Process only one job then stop (useful for cron)
php artisan queue:work --once

# Restart workers gracefully after code deploy
php artisan queue:restart
Laravel Horizon (Redis only): Horizon provides a beautiful dashboard and config-driven control over your Redis-based queues. Install it for production use.
📄terminal – horizon setup
BASH
composer require laravel/horizon
php artisan horizon:install
php artisan migrate

# Start Horizon (replaces queue:work for Redis)
php artisan horizon

# Pause / continue Horizon
php artisan horizon:pause
php artisan horizon:continue

# Access dashboard at /horizon (protected by HorizonServiceProvider gate)
📄config/horizon.php (excerpt)
PHP
'environments' => [
    'production' => [
        'supervisor-1' => [
            'connection' => 'redis',
            'queue'      => ['high', 'emails', 'default'],
            'balance'    => 'auto',
            'processes'  => 10,
            'tries'      => 3,
            'timeout'    => 60,
        ],
    ],
    'local' => [
        'supervisor-1' => [
            'connection' => 'redis',
            'queue'      => ['default'],
            'balance'    => 'simple',
            'processes'  => 3,
            'tries'      => 3,
        ],
    ],
],