İlk olarak hafiz.dev üzerinde yayımlandı.
Horizon sağlıklıydı. E-posta görevleri, bildirimler, küçük işleme görevleri, hepsi sorunsuz bir şekilde çalışıyordu. AI SDK’sını eklediniz, birkaç ajan çağrısını arka plan görevlerine sardınız ve üretime dağıttınız. Bir hafta içinde, kimsenin rapor etmediği başarısız görevler fark ettiniz, bir kullanıcı aynı AI analizini iki kez aldı ve bir Salı sabahı, beş rapor görevi aynı anda sıraya alındığında, e-posta kuyruğunuz sekiz dakika boyunca donduruldu.
Hiçbir şey istisna vermedi. Hiçbir uyarı tetiklendi. Horizon’un kontrol paneli başarısız görevlerin birkaçını gösterdi ve daha sonra her şey normale döndü. Hata durumu görünmez çünkü işçi çökmedi. İşlem ortasında öldürüldü, Horizon sessizce hatayı kaydetti ve hiçbir yığın izi, mesaj yok, hata ayıklamak için hiçbir şey yok.
Problem AI SDK’sında değil. Asıl sorun, Horizon’un varsayılan yapılandırmasının, millisecondlarla ölçülen işler için tasarlanmış olması. AI API çağrıları 30 ila 120 saniye alıyor. Yapılandırmanızdaki dört spesifik varsayılan değer, gerçeklikle sessiz bir çelişkiye yol açıyor, ve bunların üçü config/horizon.php dosyasında değil. Kod tabanınızda yer alan düzende, bakmadığınız sürece bulmanız zor. Eğer Laravel’in kuyruk sistemine yeniyseniz ve Horizon’u özel olarak ayarlamadan önce temel kavramları anlamak istiyorsanız, Laravel kuyruk işleyişi kılavuzu iş yapısı, tekrarlar ve hata yönetimini sıfırdan kapsamaktadır.
Neden AI görevleri Horizon’un varsayılanlarını bozuyor?
Neden AI görevleri Horizon’un varsayılanlarını bozuyor?
Horizon’un varsayılan denetçi yapılandırması, işlerin hızlı olduğunu varsayıyor. Bir işçi kuyruğu kontrol eder, bir iş alır, iki saniye içinde işler ve bir sonrakini alır. Varsayılanlar buna göre yansıyor: işçi öldürüldüğünde 60 saniyelik bir zaman aşımı ve bir iş stalları üzerinde değerlendirilmeden önce 90 saniye süreyle retry_after değeri ve tekrarlar arasında geri kalma gecikmesi olmaması.
AI SDK görevleri bu varsayımların her birini bozar. Tek bir Agent::run() çağrısının, araçları kullanması, yapılandırılmış çıktı üretmesi veya alt ajana devretmesi, 45 ila 90 saniye kadar sürebilir. Birden fazla sağlayıcıyı bağlayan alt ajan desenleri ile iş süresi daha da artar.
Varsayılan Horizon kurulumunda bu 90 saniyelik AI işinin ne kadar sürede çalıştığına baktığımızda:
Dördüncü adımda meydana gelen SIGKILL sessizdir. Horizon, görevleri başarısız olarak işaretler, kontrol paneli kullanıcı arayüzünde başarısızlık sayısının artması dışında görünür bir hata göstermez. Yığın izi yok, AI sağlayıcısından hiç mesaj yok, loglarınızda hiçbir PHP istisnası yok. Çoğu geliştirici, bir uygulama hatası aramak için saatler harcar çünkü iş asla hata vermedi.
Yedinci adımda çift işleme yapmak, en kötü durumdur. Laravel’in resmi Horizon dokümantasyonu bunu açıkça uyarır: “zaman aşımı değerinin, retry_after değerinden her zaman birkaç saniye daha kısa olması gerekmektedir… aksi halde, işleriniz iki kez işlenebilir.” Ancak neredeyse kimse bu uyarıyı, bir kullanıcı tekrar eden sonuçları gördüğünde okumaz.
Bu sorunun hepsini temiz bir şekilde düzeltmek için dört değişiklik yapılmalıdır.
Değişiklik 1: AI iş süresini yansıtan bir denetçi zaman aşımı ayarlayın
Değişiklik 1: AI iş süresini yansıtan bir denetçi zaman aşımı ayarlayın
Horizon’un varsayılan denetçi zaman aşımı 60 saniyedir. Bu, her denetçi yapılandırmasındaki config/horizon.php dosyasında yer alan bir değerdir. Bir iş bu süreden daha uzun sürdüğünde, işçi süreci SIGKILL alır ve zorla sonlandırılır.
// config/horizon.php: varsayılan gönderim
'supervisor-1' => [
'connection' => 'redis',
'queue' => ['default'],
'balance' => 'auto',
'processes' => 10,
'timeout' => 60, // 60 saniyeden uzun süren işleri sonlandırır
'tries' => 1,
],
AI işleri için, yavaş işçi çağrınızın gerçek üst sınırına yansıtan bir değeri yükseltin. 300 saniye (beş dakika) çoğu üretim AI yükü için mantıklı bir üst sınırdır:
'supervisor-ai' => [
'connection' => 'redis',
'queue' => ['ai'],
'balance' => 'auto',
'processes' => 3,
'timeout' => 300,
'tries' => 2,
'memory' => 512,
],
Horizon belgeleri kritik bir kısıtlamayı not eder: “Horizon zaman aşımının, iş düzeyindeki zaman aşımından daha büyük olduğundan her zaman emin olun, aksi takdirde işleriniz işlemin ortasında sonlandırılabilir.” Bu nedenle, görev sınıfında $timeout tanımlarsanız, denetçi zaman aşımı, birkaç saniye daha fazla olmalıdır.
class RunAiReportJob implements ShouldQueue
{
// Görev düzeyinde zaman aşımı:
public int $timeout = 270;
}
Görev düzeyinde zaman aşımını denetçi zaman aşımının biraz altında ayarlamak, temiz sonlandırmanın görev düzeyinde olmasını sağlar, bu da failed() yönteminin tetiklenmesini sağlar ve temizleme kancası verir. Denetçi zaman aşımından gelen bir SIGKILL, failed() işlemini atlar ve ileride olan durumların (kısmen yazılmış veritabanı satırları, temizlenmemiş geçici dosyalar, açık API oturumları) temizlenmeden kalmasına neden olur. Ara sonucu yazan veya ilerleme sütunlarını güncelleyen AI işleri için bu ayrım önemlidir.
Değişiklik 2: Tekrar işleme engellemek için retry_after değerini düzeltin
Değişiklik 2: Tekrar işleme engellemek için retry_after değerini düzeltin
Bu durum, çift kullanıcı çıktısı üreten tekil durumdur ve config/queue.php içinde yer alır; config/horizon.php dosyasında değil. Bu nedenle çoğu geliştirici bunu atlar.
retry_after değeri, Redis’in bir işin takılı kaldığını kabul etmeden önce ne kadar süre bekleyeceğini tanımlar ve varsayılan Redis bağlantısı 90 saniyedir. Denetçi zaman aşımınızı 300’e yükselttikten sonra, 90 saniyelik retry_after değeri, 90 saniyeden daha uzun süre çalışan herhangi bir işin, orijinal işler çalışmaya devam ederken tekrar kuyruğa alınmasına neden olur.
// config/queue.php: varsayılan Redis bağlantısı
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env(, ),
'retry_after' => 90, // tehlike: AI denetçi zaman aşımından kısa
'block_for' => null,
],
Laravel belgeleri bunu doğrudan ifade ediyor: zaman aşımı, retry_after‘dan daha kısa olmalıdır. Eğer denetçi zaman aşımınız 300 saniye ise, retry_after en az 360 olmalıdır:
'redis' => [
'driver' => 'redis',
'connection' => ,
'queue' => (, ),
=> 360, // denetçi zaman aşımı (300) + 60s tampon
'block_for' => null,
],
Bu değişiklik, uygulamanızda şu anda sessizce sorunlara yol açma olasılığı en yüksek olandır. Çift işleme durumu belirli bir desene sahiptir: bir kullanıcı bir AI analizini tetikler ve sonucu alır, sonra 90 saniye sonra açıklama olmadan aynı sonucu tekrar alır. Kullanıcılar tekrar eden çıktılar rapor ettiyse ve bunun bir UI hatası veya çift tıklama olduğunu varsaydınızsa, bu olabilir. İş çalıştı, öldürüldü, kuyruklandı ve tekrar baştan çalışır.
Ayrı Redis bağlantılarınız varsa, her bir kuyruk için kendi retry_after değeri, onu kullanan en yüksek denetçi zaman aşımına eşleşmelidir. redis-ai bağlantısıyla birlikte kendi retry_after değeri 360 ile temiz bir sistemdir.
Değişiklik 3: Oran sınırı hataları için üstel geri kalma ekleyin
Değişiklik 3: Oran sınırı hataları için üstel geri kalma ekleyin
AI API sağlayıcıları katı şekilde oran sınırlaması uygular. OpenAI, Anthropic ve Gemini, her biri için dakika başına belirli bir token limiti belirler. Bir iş oran sınırına ulaştığında, bir istisna atar ve başarısız olur. Geri kalma yapılandırması olmadan, Horizon hemen tekrar dener. Sürekli bir yük altındayken, bir dizi AI işinin oran sınırını aşması, her bir geri denemenin de oran sınırına çarpmasına, bunun sonucunda aşırı yükleme ve başarısız işler listesine dolmasına neden olur.
Çözüm, Horizon’un hem denetçi seviyesinde hem de görev sınıfı seviyesinde desteklediği üstel geri kalmadır.
Denetçi seviyesinde:
'supervisor-ai' => [
'connection' => ,
'queue' => [],
'balance' => ,
'processes' => 3,
'timeout' => 300,
'tries' => 3,
'backoff' => [30, 60, 120], // tekrarlar arasında 30s, sonra 60s, sonra 120s bekleyin
'memory' => 512,
],
Ya da doğrudan görev sınıfında, bu denetçi ayarlarından öncelikli olarak geçerli olur:
class RunAiReportJob implements ShouldQueue
{
public int $timeout = 270;
public int $tries = 3;
// Üstel geri kalma: ilk başarısızlıktan sonra 30s, ikinci başarısızlıktan sonra 60s
public array $backoff = [30, 60, 120];
}
Görev sınıfı yaklaşımı daha açık ve konfigürasyon değişikliklerinden etkilenmeden sürebilir. Bu, farklı AI işlerinin farklı tekrar gereksinimlerine sahip olduğu durumlarda tercih edilmelidir. Ucuz bir metin sınıflandırma işi, pahalı bir çoklu-araç ajan çağrısı daha hızlı tekrar edebilir.
Bilmeye değer bir şey: tries, toplam denemeleri sayar, tekrarları değil. $tries = 3 olan bir iş, toplamda üç şansa sahip olur: orijinal yürütme artı iki tekrar. Bir iş, bir sorun olduğunda, gerçekten bozulmadığını anlamadan API kotanızı tüketmeden önce başarısız işleri görmek için düşük tutulmalıdır. AI işlerinde oran sınırlarına sahipken genellikle doğru sayı üçtür.
Değişiklik 4: AI işlerini özel bir kuyruğa ve denetçiye taşıyın
Değişiklik 4: AI işlerini özel bir kuyruğa ve denetçiye taşıyın
Zaman aşımı ve retry_after değerleri düzeltildiğinde bile, AI işlerinin hızlı işler ile aynı denetçiyi paylaşması birbirlerini engellemeye devam eder. Bunun nedeni, eğer supervisor-1‘de üç işçi varsa ve üç tane 90 saniyelik AI işi aniden düşerse, tüm üç işçi 90 saniye boyunca meşguldür. E-posta işleri, bildirimler ve ödeme web kancaları kuyrukta kalır ve bir işçi bitene kadar bekler.
Çözüm, AI iş yükü için özel bir kuyruk ve yalnızca onu yöneten bir denetçidir ki tamamen varsayılan kuyruktan yalıtılmış durumda olsun.
// Görev sınıfınızda
class RunAiReportJob implements ShouldQueue
{
public string $queue = ;
public int $timeout = 270;
public int $tries = 3;
public array $backoff = [30, 60, 120];
}
Veya dağıtım sırasında:
RunAiReportJob::()->();
Ardından config/horizon.php dosyasında, farklı kısıtlamaları olan iki denetçi çalıştırın:
'environments' => [
=> [
// Hızlı işler: sıkı zaman aşımı, çok sayıda işçi
=> [
=> ,
=> [, ],
=> ,
=> ,
=> ,
=> ,
=> ,
=> ,
],
// AI işleri: uzun zaman aşımı, daha az işçi, daha fazla bellek
=> [
=> ,
=> [],
=> ,
=> ,
=> ,
=> ,
=> [, , ],
=> ,
],
],
],
Sonuç:
AI için üç işçi başlangıç noktasıdır. Doğru sayı, API oran sınırlarınız ve iş hacminize bağlıdır. Aynı anda üç eşzamanlı AI işi token kullanıyorsa, dakika başına limitlere hızlıca ulaşılabilir, bu nedenle işçi sayısını artırmak, önce sağlayıcınızın oran sınırını kontrol etmeden yapılmamalıdır.
Ayrıca, AI denetçisi için balance ayarını simple yapsanız daha iyi olur; auto ayarı işçi sayısını kuyruk derinliğine göre dinamik olarak ayarlama yapar, fakat bunun yan etkisi vardır: Horizon, işçi sayısını azaltmaya çalışırken “tamamlanmayan” işçileri “sürekten” kabul eder ve zaman aşımı sırasında onları zorla kapatır. Uzun süreli AI işler için simple dengeleme yaklaşımı daha tahmin edilebilir bir davranış sunar. Eşzamanlılığa kontrol edersiniz ve Horizon, aktif işleri kesintiye uğratacak şekilde derinliğe göre ayarlamaya çalışmaz.
Birden fazla iş türü arasında kuyruk topolojisini yapılandırmanın daha derin bir incelemesi için Laravel kuyruk yönlendirme kılavuzu, kuyruk atamalarını temiz bir şekilde merkezi hale getirmeyi kapsamaktadır.
Tam üretim yapılandırması
Tam üretim yapılandırması
İşte her şey bir referans olarak bir arada:
// config/queue.php: retry_after değerini en uzun AI işini karşılayacak şekilde artırın
=> [
=> ,
=> ,
=> (, ),
=> 360, // denetçi zaman aşımı (300) + 60s tampon
=> null,
],
// config/horizon.php: iki denetçi, iki endişe
=> [
=> [
=> [
=> ,
=> [, ],
=> ,
=> 10,
=> 60,
=> 3,
=> 3,
=> 256,
],
=> [
=> ,
=> [],
=> 'auto',
'processes' =>3,
'timeout' =>300,
'tries' =>3,
'backoff' =>[30,60,120],
'memory' =>512,
],
],
],
RunAiReportJob implements ShouldQueue
{
public string $queue = ;
public int $timeout = 270; // denetçi zaman aşımından biraz daha düşük
public int $tries = 3;
public array $backoff = [30, 60, 120];
public function handle(): void
{
// AI SDK çağrınızı burada yapın
}
public function failed(Throwable $exception): void
{
// Log, bildirim veya nihai başarısızlık üzerine temizleme
}
}
Dağıtım yapıldıktan sonra, yeni yapılandırmayı almak için php artisan horizon:terminate komutunu çalıştırın. Sadece queue:restart sinyali, Horizon’un denetçi yapılandırmasını yeniden yüklemez.
SSS
SSS
Horizon neden 60 saniyede görevleri öldürüyor, hiç zaman aşımı ayarlamadım?
Horizon, zaman aşımını kuyruk işçi varsayılanlarından devralır. Denetçi yapılandırmasında açık bir şekilde timeout ayarlamazsanız, işçi varsayılan olan 60 saniyeye geri döner. Bu belgelerde belirtilmiştir ama gözden kaçması kolaydır, çünkü kurulu config/horizon.php dosyasında her denetçi bloğunda timeout her zaman yer almaz. Yokluk, sıfır değildir, varsayılandır.
Sadece yüksek bir zaman aşımı ayarlayarak her yeri düzeltip ayrı denetçiler oluşturabilir miyim?
Yapabilirsiniz ama bu yanlış bir karar. E-postaların denetçisi üzerinde 300 saniyelik bir zaman aşımı ayarlamak, bir işin takılı kalması durumunda (örneğin bir e-posta sunucusu zaman aşımı nedeniyle) bir işçiyi beş dakika işgal edecek demektir. Ayrı denetçiler, her iş türü için uygun kısıtlama uygulamanızı sağlar. E-posta işlerinin AI iş zaman aşımından haberi olmamalıdır ve tersi de geçerlidir.
AI SDK işleri otomatik olarak mı gönderiyor yoksa çağrıları manuel olarak sarmalamam mı gerekiyor?
Manuel olarak sarmalamak zorundasınız. Laravel AI SDK varsayılan olarak senkron çalışır. Bir ajan çağrısını arka plan işi olarak göndermek, Agent::run() çağrısını ShouldQueue sınıfı içine sarmalamanız gereken belirgin bir mimari tercihtir. SDK otomatik olarak kuyruklara yükleme yapmaz.
Görev sınıfında $timeout aşan bir AI işine ne olur?
Eğer $timeout görev sınıfında ayarlanmış ve denetçi zaman aşımı yüksekse, iş TimeoutExceededException alır, bu da failed() yöntemini düzgün bir şekilde tetikler. Bu tercih edilen hata durumudur: temizleme kancası elde edersiniz, istisna kaydedilir ve tekrarlar normal olarak düşer. Denetçi zaman aşımından gelen bir SIGKILL tüm bunları atlar.
Yapılandırma değişikliği sonrası, zaman aşımı ve retry_after ilişkisinin doğru olduğunu nasıl doğrularım?
Denetçi zamanı aşımı ve yeniden deneme sonrası süre üzerinde, denetleyici süre aşımından kısa bir süre boyunca uyuyacak şekilde test görevi çalıştırabilirsiniz, ardından Horizon’un kontrol panelini izleyin. Eğer iş, Son İşler arasında iki kez görünüyorsa, retry_after değeri hâlâ fazla düşük demektir. Ayrıca Redis anahtarını doğrudan kontrol edin: redis-cli LRANGE queues:ai 0 -1 komutu, bir işin hem yürütme durumunda hem de kuyruğun içinde olup olmadığını gösterecektir.
Hatırlanması gereken bir şey
Hatırlanması gereken bir şey
AI SDK’sını mevcut bir Laravel uygulamasına eklemenin en büyük acısı kodda değil. Bunlardaki yapılandırma varsayımları, daha önce doğruyken sessizce yanlış duruma gelebilir. Bu dört değişiklik de karmaşık değildir. Basitçe, sorunun üretimde ortaya çıkmasına kadar bilmediğiniz değişikliklerdir.
Zaman aşımı ve retry_after ilişkisi en tehlikeli olanıdır. Resmi belgede, bilinen bir sorunla ilgili açık bir uyarı var ve yine de deneyimli geliştiricileri yakalayabiliyor çünkü iki değer farklı yapılandırma dosyalarında yer alıyor ve kullanıcı arayüzünde çapraz bir referans yok. Diğerini değiştirdiğinizde birini kontrol etmeyi bilmeniz gerekmektedir.
Kuyruk yalıtım değişikliği ise en büyük süreklilik faydasına sahiptir. AI işleriniz kendi denetçisinde çalışmaya başladığında, o denetçi üzerinde bağımsızca ayarlamalar yapabilirsiniz. AI kullanımında zirve sırasında işçi sayısını artırabilir, böylece diğer kuyrukların işlem sayısını etkilemeden yapabilirsiniz. Farklı bellek sınırları, farklı dengeleme stratejileri ve farklı uyarı eşiği ayarlayabilirsiniz. Hızlı işler ve yavaş işler sadece farklı operasyonel ihtiyaçlara sahiptir ve yapılandırma bunu yansıtır.
AI iş yüklerini şu anda ayrı denetçiler olmadan Horizon’da çalıştırıyorsanız, ilk önce retry_after değerini kontrol edin. Eğer 300’ün altında ise, zaten çift işleme yapıyor olabilirsiniz ve bunu loglarınızda göremiyorsunuz.
AI SDK ile bir şeyler inşa ederken, üretime girmeden önce kuyruk mimarisi hakkında bir inceleme istiyorsanız, iletişime geçin.
Kaynak: Orijinal Makale
- Neden AI görevleri Horizon’un varsayılanlarını bozuyor?
- Değişiklik 1: AI iş süresini yansıtan bir denetçi zaman aşımı ayarlayın
- Değişiklik 2: Tekrar işleme engellemek için retry_after değerini düzeltin
- Değişiklik 3: Oran sınırı hataları için üstel geri kalma ekleyin
- Değişiklik 4: AI işlerini özel bir kuyruğa ve denetçiye taşıyın
- Tam üretim yapılandırması
- SSS
- Hatırlanması gereken bir şey


