Lessons → Laravel Advanced → Lesson 3

Queues & Jobs

Laravel
⏱ 25 min read🔥 AdvancedNot completed

Queues allow you to defer time-consuming tasks (sending emails, processing images, making API calls) to be run in the background, keeping your app fast and responsive.

Why Use Queues?

Without Queue (Slow)
User submits form
    → PHP sends email (takes 2-3 seconds)
    → PHP resizes image (takes 1-2 seconds)
    → PHP calls external API (takes 1-3 seconds)
    → Response returned after 6-8 seconds (bad UX!)
With Queue (Fast)
User submits form
    → PHP dispatches jobs to queue (instant)
    → Response returned in milliseconds ✅
    → Queue worker processes jobs in background

Setup Queue

.env
# Use database queue (simplest setup)
QUEUE_CONNECTION=database

# Or Redis (faster, for production)
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
Terminal
# Create jobs table (for database queue)
php artisan queue:table
php artisan migrate

# Create a job class
php artisan make:job SendWelcomeEmail

Creating a Job

app/Jobs/SendWelcomeEmail.php
<?php
namespace App\Jobs;

use App\Models\User;
use App\Mail\WelcomeEmail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Support\Facades\Mail;

class SendWelcomeEmail implements ShouldQueue
{
    use Queueable;

    public int $tries = 3;          // Retry 3 times if it fails
    public int $timeout = 60;       // Max 60 seconds

    public function __construct(
        public User $user
    ) {}

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

    public function failed(Throwable $exception): void
    {
        // Log the failure, notify admin, etc.
        Log::error("Failed to send welcome email to {$this->user->email}");
    }
}

Dispatching Jobs

PHP — In Controller
<?php
// Dispatch immediately to queue
SendWelcomeEmail::dispatch($user);

// Dispatch with delay (send after 10 minutes)
SendWelcomeEmail::dispatch($user)->delay(now()->addMinutes(10));

// Dispatch to specific queue
SendWelcomeEmail::dispatch($user)->onQueue('emails');

// Dispatch only if condition is true
SendWelcomeEmail::dispatchIf($user->wantsEmails, $user);

// Dispatch synchronously (no queue, for testing)
SendWelcomeEmail::dispatchSync($user);

Running the Queue Worker

Terminal
# Start worker (processes jobs)
php artisan queue:work

# Work a specific queue
php artisan queue:work --queue=emails,default

# Process only one job then stop
php artisan queue:work --once

# In production — use Supervisor to keep worker running
# /etc/supervisor/conf.d/laravel-worker.conf
[program:laravel-worker]
command=php /var/www/html/artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true

Scheduled Tasks

app/Console/Kernel.php
<?php
protected function schedule(Schedule $schedule): void
{
    // Run every day at midnight
    $schedule->job(new CleanupOldFiles)->daily();

    // Run every hour
    $schedule->command('reports:generate')->hourly();

    // Run every Monday at 9am
    $schedule->command('emails:weekly-digest')->weeklyOn(1, '9:00');
}

// Add to crontab (runs scheduler every minute):
// * * * * * php /var/www/html/artisan schedule:run
💡
Use Redis in production! Database queues work for low traffic but Redis is much faster. On AWS, use ElastiCache for Redis. Horizon (Laravel's queue dashboard) requires Redis too.
← Previous Lesson Next Lesson →
🧠

Test your knowledge!

Take the Laravel quiz.

Take Quiz →