
Zamanlanmış bir görev iki kez tetiklendi, bir kuyruk işi yeniden denendi veya bir işçi çökmeden önce yarısını tamamladı. Sonuç: müşteriye iki fatura, iki e-posta veya iki kez düşülen bakiye.
Bu yazı, arka plan işlerini tekrara dayanıklı hâle getirmeyi ele alıyor.
İşler Neden Tekrar Çalışır?
Tekrar, bir hata değil sistemin normal davranışıdır:
- Kuyruk sistemleri yeniden dener. Hata durumunda.
- İşçi iş bitmeden çökebilir. İş tamamlanmamış sayılır.
- Zamanlanmış görev üst üste binebilir. Önceki bitmemişse.
- Ağ kopması onayı engelleyebilir. İş yapılmış ama bildirilmemiş.
- Elle tetikleme yapılabilir.
Dördüncü madde en sinsi senaryodur: iş başarıyla tamamlanmış ama tamamlandı bildirimi kuyruğa ulaşamamışsa, sistem işi başarısız sayar ve tekrar çalıştırır.
Bu durumda hiçbir hata yoktur — yine de aynı iş iki kez yapılır.
Bu yüzden doğru soru "tekrar nasıl önlenir" değil, "tekrar zararsız nasıl kılınır" olmalıdır.
Hangi İşler Zararsız?
Bazı işlemler doğası gereği tekrara dayanıklıdır:
| Zararsız | Tehlikeli |
|---|---|
| Durumu "tamamlandı" yapmak | Sayacı bir artırmak |
| Dosyayı yeniden oluşturmak | E-posta göndermek |
| Önbelleği yenilemek | Ödeme almak |
| Belirli bir değeri yazmak | Stoktan düşmek |
| Kayıt oluştur veya güncelle | Yeni kayıt eklemek |
Ayrımın özü şudur: mutlak bir değer atayan işlemler tekrara dayanıklıdır, mevcut değeri değiştiren işlemler değildir.
"Bakiyeyi 100 yap" komutu kaç kez çalışırsa çalışsın sonuç aynıdır. "Bakiyeden 10 düş" komutu ise her çalıştığında farklı sonuç verir.
Benzersiz İş Anahtarı
Tehlikeli işlemleri güvenli kılmanın temel yöntemi:
- Her iş için benzersiz bir anahtar üretin.
- İşe başlamadan önce bu anahtarı kaydedin.
- Anahtar zaten varsa işi atlayın.
- Kaydı veritabanı kısıtıyla koruyun.
Dördüncü madde yarış durumlarını önler: iki işçi aynı anda aynı işi almışsa, benzersizlik kısıtı ikincisinin kaydını reddeder ve iş yalnızca bir kez yapılır.
Uygulama kodunda "önce kontrol et, sonra yaz" yapmak bu güvenceyi vermez — iki süreç aynı anda kontrol edip ikisi de boş bulabilir.
Anahtar, işin doğasından türetilmelidir. Örneğin "sipariş 1234 için onay e-postası" gibi bir anahtar, aynı işin farklı tetiklenmelerinde de aynı olur.
Dış Servis Çağrıları
Ödeme ve mesajlaşma servisleri genellikle kendi tekrar korumasını sunar:
- İstekle birlikte benzersiz bir anahtar gönderilir.
- Servis aynı anahtarı ikinci kez görürse işlemi tekrarlamaz.
- İlk işlemin sonucunu döner.
Bu mekanizma kullanılmadığında ciddi sonuçlar doğar: ağ kopması nedeniyle yeniden denenen bir ödeme isteği, koruma yoksa müşteriden iki kez tahsilat yapar.
Bu yüzden ödeme entegrasyonlarında bu anahtarın kullanılması isteğe bağlı bir iyileştirme değil, zorunlu bir gerekliliktir.
Çakışan Zamanlanmış Görevler
Bir görev önceki çalışması bitmeden tekrar tetiklenirse:
| Çözüm | Özelliği |
|---|---|
| Dosya kilidi | Basit, tek sunucuda çalışır |
| Veritabanı kilidi | Çok sunucuda çalışır |
| Bellek deposu kilidi | Hızlı, süreli |
| Durum bayrağı | Çökmede takılı kalabilir |
Dördüncü satır yaygın bir tuzaktır: "çalışıyor" bayrağını veritabanına yazan bir görev, çökerse bayrak açık kalır ve görev bir daha hiç çalışmaz.
Bu yüzden kilitlerin bir süre sonu olmalıdır. Belirli bir süre sonra otomatik serbest kalan bir kilit, çökme durumunda sistemin kendini toparlamasını sağlar.
Yarım Kalan İşler
Uzun süren işler ortasında çökebilir. Buna karşı tasarım:
- İşi parçalara bölün. Her parça bağımsız olsun.
- İlerlemeyi kaydedin. Nereye kadar geldi?
- Kaldığı yerden devam edin.
- Her parçayı ayrı işaretleyin.
İkinci madde en kritik olanıdır: on bin kaydı işleyen bir görev, dokuz binde çökerse ilerleme kaydı olmadan baştan başlamak zorunda kalır — ve ilk dokuz bin kayıt ikinci kez işlenir.
İlerleme kaydı bu tekrarı ortadan kaldırır ve işin tamamlanmasını garanti eder.
Sıra Garantisi
Kuyruk sistemlerinde işlerin sırayla işleneceği garanti değildir:
- Birden fazla işçi paralel çalışır.
- Başarısız iş sonraya kalabilir.
- Yeniden denemeler sırayı bozar.
Bu, beklenmedik sonuçlar üretebilir: bir kaydın "oluştur" işi, "güncelle" işinden sonra işlenirse, güncelleme kaybolur.
Sıra önemliyse ya işleri tek bir kuyrukta seri işlemek ya da her işin kendi ön koşulunu kontrol etmesi gerekir. İkinci yaklaşım daha esnektir — iş, gerekli durumu bulamazsa kendini erteler.
Tekrarı Test Etmek
Dayanıklılığı doğrulamanın tek yolu denemektir:
| Test | Beklenen |
|---|---|
| Aynı işi iki kez çalıştır | Sonuç değişmemeli |
| İşi ortasında durdur | Tekrar çalışınca tamamlanmalı |
| İki işçiyi aynı anda çalıştır | Yalnızca biri işlemeli |
| Kilidi bırakmadan çök | Kilit süresi dolunca devam etmeli |
Dördüncü satır en çok gözden kaçan senaryodur: süresi dolmayan bir kilit, tek bir çökmeden sonra o görevi kalıcı olarak durdurur ve bunu haftalar sonra fark edersiniz.
Bu testleri kendi ortamınızda çalıştırmak, kuyruk ve zamanlanmış görev yapılandırmasını doğrudan yönettiğiniz sanal sunucu seçenekleri üzerinde mümkündür.
İzleme
Tekrar sorunlarını yakalamak için takip edilecekler:
- Yeniden deneme sayısı. Artıyor mu?
- Atlanan iş sayısı. Anahtar zaten var diye.
- Kilit bekleme süreleri.
- Çok uzun süren işler.
- Hiç tamamlanmayan işler.
İkinci madde koruma mekanizmasının çalıştığını doğrular: atlanan iş sayısının sıfırdan farklı olması, tekrarların gerçekten yaşandığını ve önlendiğini gösterir.
Bu sayı beklenmedik şekilde yüksekse, tekrarın kaynağını araştırmak gerekir — muhtemelen bir zaman aşımı ayarı çok kısadır.
Sonuç
Arka plan işlerinde tekrar bir hata değil normal davranıştır — iş başarıyla tamamlanıp bildirimi ulaşmazsa sistem onu başarısız sayar ve yeniden çalıştırır. Doğru soru tekrarı önlemek değil, zararsız kılmaktır. Mutlak değer atayan işlemler zaten dayanıklıdır; sayaç artırma ve e-posta gönderme gibi işlemler benzersiz iş anahtarı gerektirir ve bu anahtar veritabanı kısıtıyla korunmalıdır. Kilitlere mutlaka süre koyun: süresi dolmayan bir kilit, tek bir çökmeden sonra görevi kalıcı olarak durdurur.
Sıkça Sorulan Sorular (SSS)
İşlerim neden iki kez çalışıyor?
Kuyruk sistemleri hata durumunda yeniden dener, işçiler çökebilir ve en sinsi senaryoda iş tamamlanmış ama onay bildirimi ulaşmamıştır. Bu son durumda hiçbir hata yoktur — yine de iş tekrarlanır. Tekrarı önlemeye değil, zararsız kılmaya odaklanın.
Hangi işlemler tekrardan etkilenir?
Mevcut değeri değiştirenler. "Bakiyeyi 100 yap" kaç kez çalışsa da sonuç aynıdır; "bakiyeden 10 düş" her çalıştığında farklı sonuç verir. Sayaç artırma, e-posta gönderme, stoktan düşme ve yeni kayıt ekleme bu gruptadır.
Benzersiz anahtarı nasıl kullanmalıyım?
İşin doğasından türetin — "sipariş 1234 için onay e-postası" gibi. İşe başlamadan önce kaydedin ve kaydı veritabanı benzersizlik kısıtıyla koruyun. Uygulama kodunda "önce kontrol et sonra yaz" yapmak yeterli değildir; iki süreç aynı anda kontrol edip ikisi de boş bulabilir.
Zamanlanmış görevim bir daha hiç çalışmadı?
Muhtemelen kilit takılı kalmıştır. "Çalışıyor" bayrağını yazan bir görev çökerse bayrak açık kalır ve görev bir daha başlamaz. Kilitlere mutlaka süre sonu koyun — belirli bir süre sonra otomatik serbest kalsınlar.