PHP10m READ13 Haziran 2026

Laravel Horizon ile Redis Queue İzleme ve Yönetim

Horizon kurulumu, queue iş takibi ve başarısız job bildirimleri.

Laravel Horizon, Redis kuyruk işlemlerine gerçek zamanlı görünürlük kazandırır. Artık terminale bakarak "queue çalışıyor mu?" diye sormak zorunda değilsin — hangi job'ın çalıştığını, kaç tane beklemede olduğunu, başarısız olanları ve throughput metriklerini güzel bir dashboard'dan takip edebilirsin.

Neden Horizon?

// PLAINTEXT //
Laravel Queue (Temel):          Laravel Horizon:
• CLI ile işçi yönetimi          • Dashboard + otomatik işçi yönetimi  
• Durum takibi yok               • Job durumu, süre, throughput metrikleri
• Failed job'ları elle kontrol   • Failed job listesi ve retry butonuyla
• Ölçekleme manuel               • Redis'e göre otomatik balancing

Kurulum

// BASH //
composer require laravel/horizon
 
php artisan horizon:install
 
# Göç tabloları
php artisan migrate

config/horizon.php oluşturulur. Dashboard /horizon adresinde açılır.

İlk Yapılandırma

// PHP //
// config/horizon.php
return [
    'use'     => 'default',
    'prefix'  => env('HORIZON_PREFIX', 'horizon:'),
    'path'    => 'horizon',
    'domain'  => null,
 
    // Environment bazlı işçi tanımı
    'environments' => [
        'production' => [
            'supervisor-1' => [
                'connection' => 'redis',
                'queue'      => ['critical', 'default', 'low'],
                'balance'    => 'auto',       // Redis yüküne göre otomatik dağıt
                'minProcesses' => 1,
                'maxProcesses' => 10,
                'tries'      => 3,
                'timeout'    => 60,
            ],
        ],
 
        'local' => [
            'supervisor-1' => [
                'connection' => 'redis',
                'queue'      => ['default'],
                'balance'    => 'simple',
                'processes'  => 3,
                'tries'      => 1,
            ],
        ],
    ],
];

Queue Öncelik Sistemi

// PHP //
// config/queue.php
'redis' => [
    'driver' => 'redis',
    'connection' => 'default',
    'queue'  => env('REDIS_QUEUE', 'default'),
    'retry_after' => 90,
    'block_for'   => null,
    'after_commit' => false,
],
 
// Job'u öncelikli kuyruğa gönder
SendWelcomeEmail::dispatch($user)->onQueue('critical');
GenerateReport::dispatch($params)->onQueue('low');
ProcessPayment::dispatch($order)->onQueue('critical');

Job Sınıfı Örneği

// PHP //
// app/Jobs/SendWelcomeEmail.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;      // maksimum deneme sayısı
    public int $timeout = 30;     // saniye cinsinden zaman aşımı
    public int $backoff = 60;     // başarısız sonrası bekleme süresi (saniye)
 
    public function __construct(
        public readonly User $user,
    ) {}
 
    public function handle(): void
    {
        Mail::to($this->user)->send(new WelcomeMail($this->user));
    }
 
    public function failed(\Throwable $exception): void
    {
        // Tüm denemeler başarısız oldu — bildirim gönder
        \Log::error("WelcomeEmail gönderilemedi", [
            'user_id' => $this->user->id,
            'error'   => $exception->getMessage(),
        ]);
    }
}

Dashboard Erişim Kısıtlama

// PHP //
// app/Providers/HorizonServiceProvider.php
use Laravel\Horizon\Horizon;
 
public function boot(): void
{
    // Production'da sadece belirli e-postalar erişebilir
    Horizon::auth(function (Request $request) {
        return $request->user()?->is_admin === true;
    });
 
    // Opsiyonel: e-posta listesi
    Horizon::routeMailNotificationsTo('ops@example.com');
    Horizon::routeSlackNotificationsTo(env('SLACK_WEBHOOK'));
}

Metric ve Monitoring

// PHP //
// Horizon belli metrikleri toplar:
// - Throughput (job/dakika)
// - Runtime (ortalama işlem süresi)
// - Queue boyutu (bekleyen job sayısı)
 
// Snapshot komutu — metrikleri 5 dakikada bir kaydet
// Bunu scheduler'a ekle:
// app/Console/Kernel.php
$schedule->command('horizon:snapshot')->everyFiveMinutes();

Supervisor ile Prodüksiyon Yönetimi

// INI //
; /etc/supervisor/conf.d/horizon.conf
[program:horizon]
process_name=%(program_name)s
command=php /var/www/codeforge/artisan horizon
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/codeforge/storage/logs/horizon.log
stopwaitsecs=3600
 
; Horizon graceful restart
stopsignal=SIGTERM
// BASH //
# Supervisor komutları
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start horizon
 
# Kod deploy sonrası Horizon'ı yeniden başlat
php artisan horizon:terminate
# Supervisor otomatik yeniden başlatır

Deploy Sonrası Horizon

// YAML //
# GitHub Actions — deploy pipeline
- name: Horizon'ı yeniden başlat
  run: |
    php artisan horizon:terminate
    # Supervisor otomatik restart eder
    sleep 5
    php artisan horizon:status

Failed Job Yönetimi

// BASH //
# Tüm failed job'ları listele
php artisan queue:failed
 
# Belirli bir job'ı tekrar dene
php artisan queue:retry 5
 
# Tüm failed job'ları yeniden dene
php artisan queue:retry all
 
# Failed job tablosunu temizle
php artisan queue:flush
 
# Belli bir job'u sil
php artisan queue:forget 5
// PHP //
// Programatik retry — controller'dan
use Illuminate\Support\Facades\Artisan;
 
public function retryFailedJob(string $id)
{
    Artisan::call('queue:retry', ['id' => [$id]]);
    return back()->with('success', 'Job yeniden kuyruğa eklendi.');
}

Redis İzleme: CLI Araçları

// BASH //
# Redis'teki kuyruk boyutunu kontrol et
redis-cli llen horizon:queues:default
redis-cli llen horizon:queues:critical
 
# Horizon health check
php artisan horizon:status
# output: Horizon is running.
 
# İşçi listesi
php artisan horizon:list

Özet

Laravel Horizon; config/horizon.php'deki supervisor tanımıyla işçi sayısını Redis yüküne göre otomatik ayarlar, /horizon dashboard'uyla tüm metrikleri sunar. Prodüksiyonda Supervisor + horizon:terminate + horizon:snapshot scheduler üçlüsü şarttır. Failed job'lar dashboard'dan tek tıkla retry edilebilir — queue yönetimini gerçekten "görünür" kılan bu.