Cron görevleri, önceki çalışmanın tamamlanmasını beklemeden yeniden başlatılabildiğinde aynı işi iki kez yürütebilir. Bu durum özellikle fatura oluşturma, kuyruktan kayıt tüketme veya dış servise bildirim gönderme gibi işlemlerde yinelenen sonuçlara yol açar.
Küçük bir PHP örneğinde sorun şu şekilde görülebilir:
<?php
$orders = getPendingOrders();
foreach ($orders as $order) {
processOrder($order);
}
Görev 09:00:00'da başladığında kayıtları işlemeye devam ederken 09:00:30'da ikinci bir cron süreci başlarsa iki süreç de aynı bekleyen siparişleri okuyabilir. Kodun her iki çalışmada da hata vermeden ilerlemesi, işlemin güvenli olduğu anlamına gelmez; aynı sipariş iki kez işlenebilir.
AI incelemesinde aranacak işaretler
Kod inceleme aracına yalnızca “bu cron güvenli mi?” diye sormak yerine çalışma koşullarını açıkça vermek daha yararlıdır:
AI şu belirtileri arayabilir:Bu PHP cron görevi her dakika çalışıyor. İşlem ortalama üç dakika sürüyor ve iki ayrı süreç aynı veritabanı kayıtlarını okuyabilir. Aynı görevin eşzamanlı çalışmasını engelleyen mekanizma var mı? Kilit alınamazsa görev güvenli biçimde sonlanıyor mu? Kilidin süresi dolduğunda ne olur?
- Başlangıçta dağıtık veya süreçler arası bir kilit alınmaması.
- Kilit alınamadığında görevin devam etmesi.
- Kilit bırakma işleminin hata veya istisna durumunda garanti edilmemesi.
- Sadece bellekte tutulan bir bayrağa güvenilmesi; bunun ayrı PHP süreçlerini engellememesi.
- Sabit süreli kilidin, uzun süren bir iş sırasında sona erip ikinci sürecin başlamasına izin vermesi.
- Kilit kullanılsa bile tek tek kayıtların yeniden işlenmesini önleyecek idempotency kontrolünün bulunmaması.
Düzeltme: Kilit alınıp alınamadığını açıkça kontrol etmek
Kurgusal bir dosya kilidi uygulaması temel sorunu şöyle çözebilir:
<?php
$handle = fopen('/var/lock/order-worker.lock', 'c');
if ($handle === false || !flock($handle, LOCK_EX | LOCK_NB)) {
exit("Başka bir süreç çalışıyor.\\n");
}
try {
$orders = getPendingOrders();
foreach ($orders as $order) {
processOrder($order);
}
} finally {
flock($handle, LOCK_UN);
fclose($handle);
}
Burada LOCK_NB kilit alınamıyorsa beklemek yerine görevin sonlanmasını sağlar. Böylece ikinci süreç aynı kayıt kümesini eşzamanlı işlemeye başlamaz. finally bloğu ise normal akışta veya bir istisnada kilidin bırakılmasını güvence altına alır.
Birden fazla sunucuda çalışan uygulamalarda yerel dosya kilidi tüm süreçleri kapsamayabilir. Bu durumda paylaşılan bir kilit servisi veya veritabanının atomik kilit alma özelliği tercih edilmelidir. Kilit alınamadığında işleme devam etmek yerine ölçülebilir bir günlük kaydı yazmak ve uygun çıkış kodu döndürmek gerekir.
Kilit, aynı görevin eşzamanlı başlamasını önler; ancak görev yarıda kesildikten sonra aynı kaydın yeniden işlenmesini tek başına çözmez. İşlenen kayda benzersiz bir işlem kimliği vermek, durum geçişini koşullu yapmak veya dış servise gönderimlerde idempotency anahtarı kullanmak gerekebilir.
Doğrulama adımları
- Cron aralığını geçici olarak kısaltın veya aynı komutu iki terminalden aynı anda çalıştırın.
- İlk süreci yapay olarak yavaşlatın; örneğin test ortamında her kayıt arasında bekleme ekleyin.
- İkinci sürecin işi tekrar başlatmak yerine “başka bir süreç çalışıyor” mesajıyla sonlandığını doğrulayın.
- İlk süreçte bir istisna oluşturun ve kilidin sonrasında yeniden alınabildiğini test edin.
- İki farklı sunucudan eşzamanlı çalıştırarak seçilen kilit mekanizmasının gerçekten paylaşıldığını kontrol edin.
- Aynı sipariş için işlem sayısını ve durum değişikliklerini kaydedin; başarılı senaryoda her siparişin beklenen sayıda işlendiğini doğrulayın.
- Görev beklenenden uzun sürerse kilit zaman aşımının ikinci sürece yanlışlıkla izin vermediğini ölçün.
İlk süreç: kilidi aldı, siparişleri işliyor
İkinci süreç: kilit alınamadı, işlem yapmadan çıktı
Sonuç: her sipariş bir kez işlendiAI değerlendirmesinin belirsizliği
AI, kodda
flock()Bu nedenle AI çıktısı, kilit kapsamı, süreç ömrü, istisna davranışı, görev süresi ve kayıtların idempotent işlenmesi için ayrı sorularla sınanmalıdır. Son karar; eşzamanlı çalıştırma testi, gözlemlenebilir günlükler ve veri üzerinde yapılan tekrar işleme kontrolleriyle verilmelidir.
