📋

Tạo Jobs

Job Cơ Bản

php artisan make:job ProcessPodcast
php artisan make:job SendWelcomeEmail
<?php
// app/Jobs/SendWelcomeEmail.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;           // Số lần retry
    public int $backoff = 60;        // Delay giữa các lần retry (giây)
    public int $timeout = 120;       // Timeout (giây)
    public int $maxExceptions = 3;   // Số exception tối đa

    public function __construct(
        public User $user
    ) {}

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

    // Xử lý khi job fail
    public function failed(\Throwable $exception): void
    {
        // Log hoặc notify admin
        Log::error("Failed to send welcome email to {$this->user->email}", [
            'exception' => $exception->getMessage()
        ]);
    }

    // Điều kiện retry
    public function retryUntil(): DateTime
    {
        return now()->addHours(24);
    }
}

// Dispatch job
SendWelcomeEmail::dispatch($user);

// Dispatch với delay
SendWelcomeEmail::dispatch($user)->delay(now()->addMinutes(10));

// Dispatch vào queue cụ thể
SendWelcomeEmail::dispatch($user)->onQueue('emails');
🔗

Job Chains & Batches

Job Chaining

<?php
use Illuminate\Support\Facades\Bus;

// Jobs chạy tuần tự
Bus::chain([
    new ProcessPodcast($podcast),
    new OptimizeAudio($podcast),
    new SendPodcastNotification($podcast),
])->dispatch();

// Chain với error handling
Bus::chain([
    new ProcessOrder($order),
    new SendInvoice($order),
    new UpdateInventory($order),
])->catch(function (Throwable $e) {
    // Xử lý khi có job trong chain fail
    Log::error('Order processing failed', ['error' => $e->getMessage()]);
})->dispatch();

Job Batching (Laravel 8+)

<?php
use Illuminate\Bus\Batch;
use Illuminate\Support\Facades\Bus;
use Throwable;

// Xử lý batch jobs song song
$batch = Bus::batch([
    new ProcessImage($image1),
    new ProcessImage($image2),
    new ProcessImage($image3),
])->then(function (Batch $batch) {
    // Tất cả jobs hoàn thành
    Log::info("Batch {$batch->id} completed!");
})->catch(function (Batch $batch, Throwable $e) {
    // Có job fail
})->finally(function (Batch $batch) {
    // Batch kết thúc (dù thành công hay fail)
})->name('Image Processing')
  ->allowFailures()
  ->dispatch();

// Kiểm tra batch status
$batch = Bus::findBatch($batchId);
echo $batch->progress(); // % hoàn thành
echo $batch->pendingJobs;
echo $batch->failedJobs;
🚀

Laravel Horizon

Cài đặt Horizon (Redis)

composer require laravel/horizon

php artisan horizon:install

# Chạy Horizon
php artisan horizon
<?php
// config/horizon.php

'environments' => [
    'production' => [
        'supervisor-1' => [
            'maxProcesses' => 10,
            'balanceMaxShift' => 1,
            'balanceCooldown' => 3,
        ],
    ],
    'local' => [
        'supervisor-1' => [
            'maxProcesses' => 3,
        ],
    ],
],
💡 Production: Dùng Supervisor để giữ Horizon chạy liên tục. Dashboard tại /horizon.
← Bài 4: API Bài 6: Events →