TL;DR: Laravel 11, defer() fonksiyonunu hem geliştirdi ki bu fonksiyon, HTTP yanıtı kullanıcıya gönderildikten sonra kod çalıştırır. Kuyrulara, iş sınıflarına veya çalışanlara gerek yok. Tek yapmanız gereken, ateşle ve unut mantığındaki kodunuzu defer() içine sarın ve API’niz anında daha hızlı hale gelsin.
Geçen yıl, sipariş API uç noktamızın yanıt vermesinin 1.2 saniye sürdüğünü anlamak için iki gün harcadım. Sipariş yaklaşık 80 ms içinde oluşturuluyordu. Peki, geri kalan zaman nereye gidiyordu?
Açıkça bir onay e-postası gönderiyor; bir analiz olayı takip ediyor; üçüncü taraf bir hizmetle envanter senkronizasyonu yapıyor; bir önbellek anahtarını temizliyorduk. Tüm bunlar, yanıtlama kullanıcıya geri gönderilmeden önce eş zamanlı olarak gerçekleşiyordu.
Kullanıcı, sipariş onayını görmeden önce bu işlemlerin tamamlanmasını umursamıyordu. Tek istedikleri, siparişlerinin başarıyla geçtiğini bilmekti.
Eski Yöntem: Her Şey İçin Kuyruğa Alma
Eski Yöntem: Her Şey İçin Kuyruğa Alma
Genel tavsiye, bu görevleri bir kuyruğa itmek. Bir iş sınıfı oluşturmak. Görev oluşturmak. Bir kuyruk çalışanı çalıştırmak. İzleme kurmak. Hatalı görevleri yönetmek. Büyük bir uygulama için, karmaşık arka plan işlemleri var ise bu mantıklı.
Ancak, e-posta göndermek veya bir olayı takip etmek gibi basit ateşle ve unut görevleri için? Bu, basit olması gereken bir şey için çok fazla altyapı.
Uygulamamızda 14 farklı iş sınıfı vardı. Bunların sekizi, tek bir küçük işi yapan tek yöntemli sınıflardı. Her biri kendi dosyasına, testi ve hatalı görevler tablosunda kendi kaydına sahipti. Bu aşırı olarak hissettiriyordu.
defer() ile Tanışın
defer() ile Tanışın
Laravel 11, defer() fonksiyonunu ekledi ve bunun arka plan görevlerine bakış açımı değiştirdi. İşte nasıl çalıştığı:
Route::post('/order', function () {
$order = Order::create($data);
defer(fn() => Mail::send(new OrderConfirmation($order)));
defer(fn() => Analytics::track('order_placed', $order));
defer(fn() => InventorySync::push($order));
defer(fn() => Cache::forget("user:{$order->user_id}:cart"));
return response()->json($order);
});
Cevap kullanıcıya sipariş oluşturulduktan hemen sonra geri gönderilir. Ardından Laravel, tüm defer edilen geri çağırmaları yanıt gönderildikten sonra çalıştırır. Kullanıcı bu işlemler için beklemek zorunda kalmaz.
Hiçbir iş sınıfına ihtiyaç yok. Hiçbir kuyruğa ihtiyaç yok. Hayır Redis ya da veritabanı kuyruk sürücüsü. Sadece yanıt sonrası çalıştırılan bir closure.
defer() ve Kuyruklar Ne Zaman Kullanılır?
defer() ve Kuyruklar Ne Zaman Kullanılır?
Burada çoğu makalenin yanlış anladığı kısım. Ya “her şey için defer kullanın” ya da “her zaman kuyrukları kullanın” derler. Gerçek bunun daha incelikli olduğunu gösteriyor.
Görevi basit olduğunda ve tekrar deneme mantığına ihtiyaç duymuyorsa defer() kullanın. Bir bildirim e-postası göndermek. Bir analiz olayı takip etmek. Bir önbelleği temizlemek. Bir etkinliği kaydetmek. Eğer başarısız olursa otomatik olarak tekrar denemeye ihtiyacınız yoktur.
Kuyrukları, görev karmaşık olduğunda veya güvenilirlik garantilerine ihtiyaç duyduğunda kullanın. Bir ödemeyi işlemek. Büyük bir PDF oluşturmak. Binlerce kaydı bir harici API ile senkronize etmek. Eğer başarısız olursa bundan haberdar olmalısınız ve tekrar denemelisiniz.
Başlangıçta, bir webhook teslimatı için defer() kullanma hatasını yaptım. Webhook hedefi güvenilir değildi ve teslimatların %10’u sessizce başarısız oldu. Hiçbir tekrar deneme mekanizması yoktu. Hatalı görev için kaydı yoktu. O yüzden, bu durumu çözmek için geri kuyruk kullanmaya döndüm ve 3 tekrar ile sorunu hallettim.
Gerçek Sayılar
Gerçek Sayılar
Sipariş uç noktamızı yeniden yapılandırdıktan sonra defer() kullanarak kritik olmayan görevlerde:
- Yanıt süresi 1.2 saniyeden 280 ms’ye düştü
- Kullanıcı tarafından algılanan performans dramatik bir şekilde iyileşti
- 8 tane tek yöntemli iş sınıfını sildik
- Kuyruk çalışanı yükü azaldı çünkü daha az iş gönderiliyordu
E-posta hala gönderiliyor. Analiz olayı hala takip ediliyor. Önbellek hala temizleniyor. Kullanıcı bunlar için hiçbir zaman beklemedi.
Her Projede Kullandığım Bir Model
Her Projede Kullandığım Bir Model
Benim için, yaygın istek seviyesindeki görevleri erteleyen basit bir middleware oluşturuyorum.
class DeferCommonTasks
{
public function handle($request, Closure $next)
{
$response = $next($request);
defer(fn() => ActivityLog::record($request));
defer(fn() => MetricsCollector::trackRequest($request, $response));
return $response;
}
}
Her istek, otomatik olarak etkinlik kaydeder ve metrikleri takip eder ve yanıta ek bir gecikme eklemez. Middleware bir defa çalışır ve her uç nokta bundan faydadır.
Farklı Olsaydım Ne Yapardım
Farklı Olsaydım Ne Yapardım
Başından itibaren net bir kural belirlerdim. Eğer görev tekrar denemeye ihtiyaç duymuyorsa ve 5 saniyeden az sürüyorsa defer() kullanın. Eğer tekrar denemeye veya daha uzun sürüyorsa bir kuyruk kullanın. Bu kuralın erken belirlenmesi, sonunda karşılaştığımız 14 gereksiz iş sınıfından kaçınmamıza yardımcı olurdu.
Ayrıca defer() kullanıyorsanız, veritabanı işlemleri içinde kullanmaktan kaçınırdım. Eğer işlem geri alınırsa, defer edilen geri çağırma yine çalışır çünkü yanıt sonrası yürütülür. Bu da, sipariş onay e-postalarını başarısız olan siparişler için göndermemize neden olmuştu. Bunu zor şekilde öğrendim.
Genel Sonuç
Genel Sonuç
defer() kuyruklar için bir ikame değildir. Sadece yanıt sonrası çalıştırmak için var olan küçük iş sınıflarının yerini alır.
Bir satır kod. Hiçbir altyapı değişikliği. Ölçülebilir daha hızlı yanıtlar.
Laravel 11 veya sonrası bir sürümdeyseniz ve henüz defer() kullanmıyorsanız, kullanıcılarınızı bekletiyorsunuz demektir. Laravel uygulamalarınızda bulduğunuz en basit performans kazanımı nedir?
Kaynak: Orijinal Makale


