Kaynak: hafiz.dev
Laravel uygulamalarının çoğu, bir süre sonra karmaşık bir kuyruğa dönüşüyor. Öncelikle temiz bir başlangıç yapıyorsunuz: tek bir varsayılan kuyruk, tüm işler oraya gidiyor, hayat basit. Sonra bir müşteri, e-postaların yavaş olduğunu şikayet ediyor, bu yüzden özel bir emails kuyruğu oluşturuyorsunuz. Sonra Stripe web kancaları birikmeye başlıyor, bu nedenle billing kendi kuyruğunu alıyor. Ardından AI işlem görevleri ortaya çıkıyor ve her şeyi yiyor, bu yüzden heavy noktası daha güçlü bir Redis bağlantısına yönlendiriliyor.
Altı ay sonra, kuyruk topolojiniz birden fazla yerde yaşıyor: bazı iş sınıflarındaki $queue özelliklerinde, denetleyicilerde ve planlı komutlarda dağılmış ->onQueue() zincirlerinde ve yapılandırılmamış bazı işlerin varsayılan kuyrukta sessizce düşmesi. Bir kuyruk adını değiştirdiğinizde, tüm kod tabanını taramak zorunda kalıyorsunuz. Yeni bir geliştirici eklediğinizde, nereye bakacağını bilmeden geliyor. “ProcessInvoice nereye gidiyor?” sorusunun cevabı: yazana bağlı olarak her yere gider.
Laravel 13 ile birlikte Queue::route() geliyor. RateLimiter::for() oran limitleri veya Route::model() model bağlama için aynı felsefe. Altyapı yapılandırması tek bir yerde olmalı, yirmi iş sınıfında dağılmamalı. Bu, on bir kuyruk ve sıfır tutarlılık olan bir SaaS kod tabanını temizlerken istediğim bir yazıydı.
Muhtemelen Şu Anda Karıştırdığınız İki Model
Muhtemelen Şu Anda Karıştırdığınız İki Model
Öncelikle Queue::route() kullanılmadan önce, belli bir kuyrukta işlem yapmanız gerektiğinde iki gerçek seçeneğiniz vardı.
Birinci seçenek: sınıf özellikleri. Çalışır, ancak iş sınıfını altyapını bilgilendirilmiş hale getiriyor.
class ProcessInvoice implements ShouldQueue
{
use Queueable;
public string $queue = 'billing';
public string $connection = 'sqs';
}
ProcessInvoice işinizin üretimde SQS kullandığını, test ortamında ise veritabanı kullandığını bilmemesi gerekir; bu bir çevre sorunudur, iş mantığı sorunu değildir. Eğer bu işi farklı bir kuyruğa taşımak isterseniz, sınıfın kendisine dokunmanız gerekir. Bu, iş mantığı değişmediği sürece olmamalıdır. Altyapıyı yeniden organize etmek için değil.
İkinci seçenek: dağıtımda zincirleme. Altyapı bilgisini arayıcıya kaydırıyor.
ProcessInvoice::dispatch($invoice)
->onQueue('billing')
->onConnection('sqs');
Artık bu işi dağıtan her denetleyici, komut ve dinleyici doğru kuyruk ve bağlantıyı zincirlemeyi hatırlamak zorundadır. Bir çağrı noktasını atladığınızda, görev sessizce varsayılan kuyruğa düşer. Hiçbir hata olmaz, uyarı yok. Yavaş faturalama süreci ve billing Horizon işçisini boşta izleyen bir geliştirici varsa, işlerin yavaş yavaş birikmesi oluyor.
Uygulamalar genellikle her iki modeli karıştırma eğilimindedir. Bazı işler sınıf özelliklerini kullanır, bazıları dağıtım zincirlerini kullanır. Bazıları her iki yerde de yer alır ve biri diğerini hatırlamadan geçersiz kılar. Yeni birine katılırken, bakacak mantıklı bir yer yoktur. Sadece tarayıp umut etmeniz gerekir.
Queue::route(), her iki modeli tek bir model ile değiştirir.
Queue::route() Nasıl Çalışır
Queue::route() Nasıl Çalışır
Kuyruk topolojinizi bir kez kaydedersiniz, AppServiceProvider::boot() içinde:
use Illuminate\Support\Facades\Queue;
public function boot(): void
{
Queue::route(ProcessInvoice::class, connection: 'sqs', queue: 'billing');
Queue::route(SendWelcomeEmail::class, queue: 'emails');
Queue::route(GenerateReport::class, connection: 'redis', queue: 'heavy');
Queue::route(ProcessPodcast::class, queue: 'media');
}
Tamam. Artık ProcessInvoice‘nin her dağıtımı otomatik olarak billing kuyruğuna, sqs bağlantısı ile yönlendirilir, bunu hangi kod tabanında dağıttığınızın önemi yok. Zincirleme yok. Sınıf özellikleri gerekli değil.
// Billing/sqs'ye otomatik olarak gider
ProcessInvoice::dispatch($invoice);
// Bu da öyle, uygulamanın herhangi bir yerinden
dispatch(new ProcessInvoice($invoice));
İş sınıfı temiz kalır:
class ProcessInvoice implements ShouldQueue
{
use Queueable;
public function __construct(
public readonly Invoice $invoice,
) {}
public function handle(): void
{
// sadece iş mantığı burada
}
}
Hiçbir $queue yok. Hiçbir $connection yok. Faturalama mantığı ile ilgili olan bir sınıfın üst kısmında altyapı gürültüsü yok.
Laravel, ayrıca toplu kayıt için bir dizi kısayol da gönderir:
Queue::route([
ProcessInvoice::class => ['billing', 'sqs'], // kuyruk + bağlantı
SendWelcomeEmail::class => 'emails', // kuyruk yalnızca, varsayılan bağlantı
GenerateReport::class => ['heavy', 'redis'],
]);
Her iki stil de çalışıyor. Ben, satır bazında yaklaşımı tercih ediyorum çünkü kod incelemesinde fark etmek daha kolay. Ancak dizi söz dizimi, servis sağlayıcınız uzun hale geldiğinde faydalı olabilir.
Gerçekten Zeki Kısım: Arayüz ve Trait Yönlendirme
Gerçekten Zeki Kısım: Arayüz ve Trait Yönlendirme
Bireysel iş sınıflarını yönlendirmek faydalıdır. Ancak arayüzle yönlendirme daha da güçlü bir hale geliyor, özellikle uygulamanız büyüdüğünde.
Diyelim ki, faturalama sisteminize ait bir düzine işiniz var: ProcessInvoice, RefundPayment, ChargeSubscription, GenerateReceipt vs. Her birini bireysel olarak kaydedebilirsiniz. Ama her yeni faturalama işini eklediğinizde AppServiceProvider‘ı güncellemek zorundasınız. Bu, kaçınmaya çalıştığınız aynı bakım yüküdür.
Bunun yerine, bir işaretçi arayüzü oluşturabilirsiniz:
namespace App\Contracts;
interface BillingJob {}
Her faturalama işinde bunu uygulayın:
class ProcessInvoice implements ShouldQueue, BillingJob
{
use Queueable;
// ...
}
class RefundPayment implements ShouldQueue, BillingJob
{
use Queueable;
// ...
}
class ChargeSubscription implements ShouldQueue, BillingJob
{
use Queueable;
// ...
}
Sonra bir kez kaydedin:
Queue::route(BillingJob::class, connection: 'sqs', queue: 'billing');
BillingJob arayüzünü uygulayan her iş, otomatik olarak faturalama/SQS’ye yönlendirilir. Yarın yeni bir faturalama işi ekleyin, arayüzü uygulayın ve doğru bir şekilde yönlendirilir. Hizmet sağlayıcısında herhangi bir değişiklik yapmaya gerek yok.
Aynı model, üst sınıflarla da çalışır, arayüzler yerine mirası tercih ederseniz:
abstract class BillingJob implements ShouldQueue
{
use Queueable;
}
class ProcessInvoice extends BillingJob {}
class RefundPayment extends BillingJob {}
Ya da bileşen tercih ederseniz, trait’lerle:
trait IsBillingJob {}
Queue::route(IsBillingJob::class, connection: 'sqs', queue: 'billing');
İşlerinizi nasıl organize ettiğinize göre hangisini seçebilirsiniz. Yönlendirme çözümü, somut bir sınıf, arayüz, trait veya üst sınıf geçirip geçirmediğinize bakılmaksızın aynı şekilde çalışır.
Elde edilen her kuralın bir önceliği vardır: doğrudan sınıf kaydı her zaman arayüz eşleşmesinden daha ağır basar. Yani eğer BillingJob‘u billing/sqs‘ya yönlendirirseniz, ama sonra ProcessInvoice‘yi billing-priority/sqs‘ye işaret eden belirli bir yönlendirme ekliyorsanız, o sınıf için daha spesifik kural kazanır, diğerleri ise arayüz yönlendirmesini kullanmaya devam eder. Özel, genelden daha ağır basar. Bu, bekleyeceğiniz bir davranıştır.
Bir Görsel: Dağıtım Çözümü Nasıl Çalışır
Bir Görsel: Dağıtım Çözümü Nasıl Çalışır
Queue::route() yapılandırmasını yapıp, ne olduğunu görmek için tam resim:
flowchart LR
A[ProcessInvoice::dispatch] --> R{Queue::route resolver}
B[RefundPayment::dispatch] --> R
C[SendWelcomeEmail::dispatch] --> S{Queue::route resolver}
D[GenerateReport::dispatch] --> T{Queue::route resolver}
R --> F[billing queue / SQS]
S --> G[emails queue / default]
T --> H[heavy queue / Redis]
Her dağıtım, çözücü üzerinden geçer. Çözücü, iş sınıfını kaydedilmiş yönlendirmelerle, ardından arayüzler, traitler ve üst sınıflarla kontrol eder. İlk eşleşme kazanır. Eşleşme yoksa, görev bağlı olduğu varsayılan kuyrukta düşer, tam olarak önceki gibi.
Dağıtım çağrı noktalarınız, uygulamanın neresinde olursa olsun temiz kalır.
Gerçek Bir Önce ve Sonra
Gerçek Bir Önce ve Sonra
İşte bu değişiklikten önce, üç kuyruk olan tipik bir uygulama ile birlikte görünüm. Dört dağıtım, dört farklı model:
// InvoiceController.php
ProcessInvoice::dispatch($invoice)
->onQueue('billing')
->onConnection('sqs');
// RefundController.php: biri onConnection'ı unuttu, üretimde yanlış bağlantı
RefundPayment::dispatch($refund)->onQueue();
// SendWelcomeEmail.php: iş sınıfında kodlanmış özellik
class SendWelcomeEmail implements ShouldQueue
{
public string $queue = ;
}
// ReportCommand.php: hiç yönlendirme yok, sessizce varsayılan kuyruğa düşüyor
GenerateReport::dispatch();
Refaktörlemeden sonra, AppServiceProvider tek bir doğruluk kaynağı haline geliyor:
public function boot(): void
{
Queue::route(BillingJob::class, connection: , queue: );
Queue::route(SendWelcomeEmail::class, queue: );
Queue::route(GenerateReport::class, queue: );
}
Artık her dağıtım yeri aynı temiz çağrı olur:
ProcessInvoice::dispatch();
RefundPayment::dispatch();
SendWelcomeEmail::dispatch();
GenerateReport::dispatch();
RefundPayment bağlantı hatası giderildi. Sessiz GenerateReport yönlendirme problemi düzeltildi. Ve kod tabanını okuyan herkes kuyruk yapılandırması için tam olarak nereye bakacaklarını biliyor.
Mevcut Bir Uygulamayı Geçiştirmek
Mevcut Bir Uygulamayı Geçiştirmek
Eğer Laravel 13’e yükseltiyorsanız, bu refaktör, güncelleme ile iyi bir şekilde birleşir. Laravel 12’den 13’e yükseltme kılavuzu yükseltme sürecini kapsar; bu refaktör, hemen ardından veya sırasında kullanılabilir.
Başlangıçta, iş sınıflarınızdaki her $queue ve $connection özelliğini bulun:
grep -rn
grep -rn
Kaynak: Orijinal Makale


