İş Kuyruğu (Job Queue) Nedir?
Kısa tanım
İş kuyruğu (job queue), e-posta gönderimi, PDF üretimi veya görsel işleme gibi kullanıcının beklemesine gerek olmayan işleri arka plan görevi (background job) olarak kaydeden ve bunları ayrı çalışan worker süreçlerine dağıtan yapıdır. Web isteği hızla yanıt dönerken iş arka planda yürür. Başarısız işler belirlenen kurallarla yeniden denenir; her işin durumu da izlenebilir.
Diğer adları: job queue, arka plan işi, background job, worker, görev kuyruğu, task queue

İstekten ayrılan iş
Bir kullanıcı “raporu indir” butonuna bastığında rapor 40 saniyede hazırlanıyorsa, bu işi HTTP isteğinin içinde yapmak birkaç soruna yol açar: tarayıcı veya proxy zaman aşımına düşer, sunucudaki istek işleyicileri meşgul kalır, kullanıcı sayfayı yenilediğinde iş baştan başlar. İş kuyruğu bu işi istekten ayırır. Uygulama yalnızca “şu rapor üretilsin” kaydını kuyruğa ekler ve kullanıcıya hemen “hazırlanıyor” yanıtını döner. Ayrı çalışan bir worker süreci işi kuyruktan alır, tamamlar ve sonucu kaydeder.
Tipik arka plan işleri şunlardır: işlem e-postaları, görsel küçültme ve dönüştürme, dışa aktarma dosyaları, üçüncü taraf servislere senkronizasyon, toplu bildirimler ve yavaş çalışan analizler.
Mesaj kuyruğundan farkı
Mesaj kuyruğu servisler arasında veri taşıyan genel bir altyapıdır; iş kuyruğu ise onun üzerine kurulan, uygulama düzeyinde bir soyutlamadır. Bir iş kaydı yalnızca bir mesaj değildir: adı, parametreleri, durumu, deneme sayısı, son hatası ve çalıştırılacağı zaman vardır. İş kuyruğu kütüphaneleri (Node.js için BullMQ, Ruby için Sidekiq, Python için Celery gibi) bu durumu çoğunlukla Redis veya bir veritabanı üzerinde tutar ve yeniden deneme, gecikmeli çalıştırma, öncelik ve eşzamanlılık sınırlarını hazır sunar.
Bir işin yaşam döngüsü
| Durum | Anlamı |
|---|---|
| Bekliyor (waiting) | Kuyruğa eklendi, boş bir worker bekliyor |
| Gecikmeli (delayed) | Belirli bir zamanda veya yeniden deneme beklemesinden sonra çalışacak |
| Çalışıyor (active) | Bir worker tarafından alındı ve kilitlendi |
| Tamamlandı (completed) | Başarıyla bitti; sonuç kaydedildi |
| Başarısız (failed) | Deneme hakkı tükendi; inceleme bekliyor |
“Çalışıyor” durumundaki bir işin worker'ı çökerse iş sonsuza kadar bu durumda kalmamalıdır. Kuyruk sistemleri bunu bir kilit süresi veya kalp atışı (heartbeat) ile çözer: süre dolunca iş tekrar alınabilir hâle gelir.
Yeniden deneme ve idempotency
Arka plan işleri genellikle ağa, dış API'lere ve diğer servislere bağımlıdır; geçici hatalar kaçınılmazdır. İyi bir yeniden deneme politikası şunları ayırt eder:
- Geçici hata: Zaman aşımı, 429 Too Many Requests, 503 gibi yanıtlar. Üstel artan bekleme süreleriyle (ör. 10 sn, 1 dk, 5 dk) ve biraz rastgelelik eklenerek tekrar denenir.
- Kalıcı hata: Geçersiz veri, silinmiş kayıt, yetki hatası. Tekrar denemek sonuç değiştirmez; iş doğrudan başarısız sayılmalı ve bir alarm üretmelidir.
Yeniden denemenin doğal sonucu, aynı işin birden fazla kez çalışabilmesidir. Worker e-postayı gönderdikten sonra, işi “tamamlandı” olarak işaretleyemeden çökerse e-posta ikinci kez gider. Bu yüzden işler idempotent tasarlanmalıdır: “bu sipariş için onay e-postası gönderildi mi?” bilgisini kaydetmek veya dış servise idempotency anahtarı göndermek gibi.
Worker sayısı ve eşzamanlılık
Worker sayısını artırmak kuyruğu hızlandırır, ama sınırsız değildir. Her worker veritabanı bağlantısı ve bellek tüketir; işler bir dış API'yi çağırıyorsa o API'nin hız sınırları asıl darboğaz olur. Bu nedenle kuyruklar çoğu zaman türüne göre ayrılır: hızlı ve kritik işler (şifre sıfırlama e-postası) ayrı, uzun ve ağır işler (toplu dışa aktarma) ayrı bir kuyrukta ve ayrı eşzamanlılık ayarıyla çalışır. Böylece tek bir ağır iş dalgası kritik e-postaları geciktirmez.
Veritabanıyla basit bir iş kuyruğu
Küçük ve orta ölçekli projelerde ayrı bir altyapı kurmadan, mevcut PostgreSQL veritabanında bir tablo iş kuyruğu olarak kullanılabilir. Önemli olan, iki worker'ın aynı işi almamasıdır. PostgreSQL'in FOR UPDATE SKIP LOCKED ifadesi, başka bir worker'ın kilitlediği satırları atlayarak bunu sağlar:
BEGIN;
SELECT id, tur, parametreler
FROM isler
WHERE durum = 'bekliyor' AND calisma_zamani <= now()
ORDER BY calisma_zamani
LIMIT 1
FOR UPDATE SKIP LOCKED;
-- işi çalıştır, ardından:
UPDATE isler SET durum = 'tamamlandi' WHERE id = $1;
COMMIT;Belirli saatlerde tekrarlanan işler için kuyruğun yanında bir zamanlayıcı da gerekir; klasik yöntem cron'dur, birçok iş kuyruğu kütüphanesi ise tekrarlanan işleri kendi içinde tanımlamaya izin verir.

