Merhaba arkadaşlar, bugün başımı çok ağrıtan bir sorunu ve nasıl çözdüğümü anlatacağım. Kullanıcı bir CSV dosyası yüklediğinde, içindeki binlerce kaydı işlemem gerekiyordu. İlk başta bunu normal bir HTTP isteği içinde yapıyordum ve tabii ki 504 Gateway Timeout hatası yiyordum. Kullanıcı da "sayfa yanıt vermiyor" diye şikayet ediyordu. İşte o zaman Laravel'in queue sisteminin gücünü hatırladım.
Sorunun Tam Olarak Neresiydi?
Sorun şuydu: Kullanıcıdan gelen dosyayı işlemek 2-3 dakika sürüyordu ve bu süre boyunca HTTP bağlantısı açık kalıyor, sunucu kaynakları bloke oluyordu. Bu, hem kötü bir kullanıcı deneyimi hem de ölçeklenebilirlik felaketi demekti. Laravel queue'ları tam da bu noktada devreye giriyor. İşi bir kuyruğa alıyorsunuz, anında kullanıcıya "İşleminiz başladı" yanıtını dönüyorsunuz, gerisini arka planda çalışan worker'lar hallediyor.
İlk Adım: Job ve İş Kuyruğu Oluşturmak
İlk yapmanız gereken, arka planda çalıştırmak istediğiniz işlemi bir Job sınıfına dönüştürmek. Artisan komutu ile kolayca oluşturabilirsiniz.
Oluşan Job sınıfının içini, uzun süren iş mantığınızla dolduruyorsunuz. Örneğin:
İkinci Adım: Job'ı Kuyruğa Almak ve Worker'ı Çalıştırmak
Controller'ınızda, artık bu uzun işlemi doğrudan yapmak yerine, job'ı kuyruğa alıyorsunuz. Bu, anında gerçekleşir.
Şimdi sıra, kuyruktaki işleri işleyecek worker'ı çalıştırmakta. Terminalde şu komutu çalıştırın:
Bu komut, sürekli çalışarak kuyrukta bekleyen job'ları alır ve handle() metodunu çalıştırır. Production ortamında bunu bir Supervisor ile yönetmeniz şiddetle tavsiye edilir, worker'ın ölmesi durumunda otomatik yeniden başlatır.
Pro İpuçları ve Yaşadığım Tuzaklar
- Queue Driver Seçimi: Geliştirme ortamında `sync` driver kullanmak işinizi görebilir ama production'da database, redis veya beanstalkd gibi gerçek bir driver kullanın. Ben Redis'i tercih ediyorum, çok hızlı.
- Failed Jobs: Mutlaka `php artisan queue:failed-table` ve `php artisan queue:work --tries=3` gibi ayarları kullanın. Job başarısız olursa logs'a düşsün, tekrar denensin.
- İlerleme Takibi: Kullanıcıya "İşlem şu kadar tamamlandı" demek isterseniz, job içinden bir event fırlatıp, bunu Laravel Echo ve WebSocket ile dinleyebilirsiniz. Bu biraz daha ileri seviye bir konu.
Sonuç olarak, Laravel queue sistemi sayesinde artık kullanıcılarımız anında yanıt alıyor, sunucumuzun kaynakları verimli kullanılıyor ve en önemlisi ben rahat uyuyabiliyorum.
Peki ya siz? Laravel'de uzun süren işlemleri nasıl yönetiyorsunuz? Hiç queue konfigürasyonunda beklenmedik bir tuzakla karşılaştınız mı? Yorumlarda deneyimlerinizi paylaşın!
Sorun şuydu: Kullanıcıdan gelen dosyayı işlemek 2-3 dakika sürüyordu ve bu süre boyunca HTTP bağlantısı açık kalıyor, sunucu kaynakları bloke oluyordu. Bu, hem kötü bir kullanıcı deneyimi hem de ölçeklenebilirlik felaketi demekti. Laravel queue'ları tam da bu noktada devreye giriyor. İşi bir kuyruğa alıyorsunuz, anında kullanıcıya "İşleminiz başladı" yanıtını dönüyorsunuz, gerisini arka planda çalışan worker'lar hallediyor.
İlk yapmanız gereken, arka planda çalıştırmak istediğiniz işlemi bir Job sınıfına dönüştürmek. Artisan komutu ile kolayca oluşturabilirsiniz.
Bash:
php artisan make:job ProcessCsvUpload
Oluşan Job sınıfının içini, uzun süren iş mantığınızla dolduruyorsunuz. Örneğin:
PHP:
<?php
namespace App\Jobs;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ProcessCsvUpload implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $filePath;
public function __construct($filePath)
{
$this->filePath = $filePath;
}
public function handle()
{
// Uzun süren CSV işleme mantığı buraya gelir.
$file = fopen(storage_path('app/' . $this->filePath), 'r');
while (($data = fgetcsv($file)) !== false) {
// Her bir satır için veritabanı işlemi, API çağrısı vs.
User::create([
'name' => $data[0],
'email' => $data[1],
// ...
]);
// İşlemin ilerlemesini takip etmek için event fırlatabilirsiniz.
}
fclose($file);
// İşlem bittiğinde geçici dosyayı silebilirsiniz.
unlink(storage_path('app/' . $this->filePath));
}
}
Controller'ınızda, artık bu uzun işlemi doğrudan yapmak yerine, job'ı kuyruğa alıyorsunuz. Bu, anında gerçekleşir.
PHP:
// Dosya yüklendikten sonra...
$filePath = $request->file('csv_file')->store('csv_uploads');
// Job'ı kuyruğa al
ProcessCsvUpload::dispatch($filePath);
// Hemen kullanıcıya yanıt dön
return response()->json(['message' => 'Dosyanız işleme alındı. Tamamlandığında bilgilendirileceksiniz.']);
Şimdi sıra, kuyruktaki işleri işleyecek worker'ı çalıştırmakta. Terminalde şu komutu çalıştırın:
Bash:
php artisan queue:work
Bu komut, sürekli çalışarak kuyrukta bekleyen job'ları alır ve handle() metodunu çalıştırır. Production ortamında bunu bir Supervisor ile yönetmeniz şiddetle tavsiye edilir, worker'ın ölmesi durumunda otomatik yeniden başlatır.
- Queue Driver Seçimi: Geliştirme ortamında `sync` driver kullanmak işinizi görebilir ama production'da database, redis veya beanstalkd gibi gerçek bir driver kullanın. Ben Redis'i tercih ediyorum, çok hızlı.
- Failed Jobs: Mutlaka `php artisan queue:failed-table` ve `php artisan queue:work --tries=3` gibi ayarları kullanın. Job başarısız olursa logs'a düşsün, tekrar denensin.
- İlerleme Takibi: Kullanıcıya "İşlem şu kadar tamamlandı" demek isterseniz, job içinden bir event fırlatıp, bunu Laravel Echo ve WebSocket ile dinleyebilirsiniz. Bu biraz daha ileri seviye bir konu.
Sonuç olarak, Laravel queue sistemi sayesinde artık kullanıcılarımız anında yanıt alıyor, sunucumuzun kaynakları verimli kullanılıyor ve en önemlisi ben rahat uyuyabiliyorum.
Peki ya siz? Laravel'de uzun süren işlemleri nasıl yönetiyorsunuz? Hiç queue konfigürasyonunda beklenmedik bir tuzakla karşılaştınız mı? Yorumlarda deneyimlerinizi paylaşın!