Yoğun bakımda yatan ve tansiyonu düşen kritik bir hastanın başına otomatik bir robotik ilaç infüzyon pompası bağlandığını hayal edin. Nöbetçi asistan sisteme şu emri girer: "Hastanın damarına her 60 saniyede bir güçlü bir vazopressör (damar büzücü) dozu enjekte et!" Normalde verilen her dozun 30 saniye içinde vücut tarafından emilmesi ve tansiyonun dengelenmesi beklenir. Ancak hastanın damar yolu bükülür veya periferik dolaşım tıkandığı için verilen ilk doz damardan dokuya geçemez, damarın içinde asılı kalır. Pompa ise acımasız bir mekanik saat gibi çalışmaya devam eder: 60 saniye sonra ikinci dozu basar, 120 saniye sonra üçüncü dozu basar, 300 saniye sonra beşinci dozu basar! Önceki dozlar emilmeden arkadan gelen kimyasallar damar yatağını tıka basa doldurur; sonunda damar basınca dayanamayıp çatlar, hasta masif bir toksik şokla arrest olur. Asistanın "Ben sadece dakikada bir çalışacak şekilde ayarlamıştım" savunması, kontrolsüz bir otomasyonun hastayı öldürdüğü gerçeğini değiştiremez.

Linux sistem mühendisliğinde ve web geliştiriciliğinde /etc/crontab dosyasına zaman aşımı (timeout) ve kilit mekanizması (flock) koymadan her dakika çalışan bir PHP, Python veya Bash betiği eklemek, tam olarak bu tıkalı damara durmaksızın ilaç basan robotik pompanın dijital cinayetidir.


"Her Dakika Çalışsın" Masumiyeti

Geliştirici e-ticaret sitesine yeni bir özellik ekler: Sipariş senkronizasyonu, harici bir pazar yerinden (Trendyol, Hepsiburada, Amazon) stok güncelleme veya SMS bildirim kuyruğu.

Geliştirici terminalde crontab -e yazar ve o meşhur satırı ekler:

# Her dakika pazar yeri stoklarını senkronize et:
* * * * * /usr/bin/php /var/www/site/sync_stock.php > /dev/null 2>&1

Geliştirici kendi lokal bilgisayarında test etmiştir; betik 3 saniyede tamamlanmaktadır. Geliştirici arkasına yaslanır: "Harika, stoklarımız artık her dakika güncel!"

Oysa geliştiricinin unuttuğu şey, dış dünyanın (üçüncü taraf API'lerin) her zaman 3 saniyede yanıt vermeyeceğidir.


Patolojinin Gelişimi: Tsunami Dalgası Nasıl Başlar?

Salı günü saat 14:00'te Trendyol veya entegrasyon yapılan kargo firmasının API sunucusu aşırı yükten dolayı yavaşlar veya kilitlenir.

Ve dakika dakika o felaket çarkı dönmeye başlar:

[14:00:00 - SÜREÇ 1 BAŞLADI]
- sync_stock.php çalıştı.
- Karşı API'ye HTTP cURL isteği attı: "Stokları ver!"
- Karşı API yanıt vermiyor... cURL zaman aşımı (timeout) tanımsız!
- Süreç 1 beklemeye başladı (State: S / Sleeping).
          │
          ▼
[14:01:00 - CRON TETİKLENDİ: SÜREÇ 2 BAŞLADI!]
- Cron umursamazdır: Saat 14:01 oldu mu? Evet!
- İkinci bir sync_stock.php çalıştırılır!
- O da karşı API'ye istek attı, o da askıda kaldı!
- Sunucuda aktif çalışan süreç sayısı: 2.
          │
          ▼
[14:15:00 - 15 DAKİKA GEÇTİ!]
- Sunucuda AYNI ANDA ÇALIŞAN TAM 15 ADET sync_stock.php süreci var!
- Her biri 80 MB RAM ve birer MySQL bağlantısı tutuyor!
          │
          ▼
[14:45:00 - VE SONUÇ: FORK BOMB VE ZİNCİRLEME İFLAS!] 🔴
- Sunucuda 45 ADET kilitlenmiş PHP süreci!
- MySQL max_connections (151) tükendi!
- RAM tamamen doldu, Swap patladı!
- Linux Kernel yeni hiçbir süreç açamaz hale geldi:
  "-bash: fork: Cannot allocate memory"
- Nginx çöktü, web sitesi kapandı, SSH bağlantısı kilitlendi!

Karşı tarafın API'sinin 45 dakika yavaşlaması, sizin sunucunuzun kendi kendini bir Fork Bomb gibi yiyip bitirmesiyle ve intihar etmesiyle sonuçlanmıştır.


Semptom: Kendi Süreçlerinin Altında Ezilen Sunucu

Sunucu çöktüğünde sistem yöneticisi terminale girmeyi başarırsa ve ps aux | grep php yazarsa ekrana düşen liste tüyler ürperticidir:

root  14201  0.2  1.4  /usr/bin/php sync_stock.php (Başlangıç: 14:00)
root  14389  0.2  1.4  /usr/bin/php sync_stock.php (Başlangıç: 14:01)
root  14512  0.2  1.4  /usr/bin/php sync_stock.php (Başlangıç: 14:02)
...
root  28912  0.2  1.4  /usr/bin/php sync_stock.php (Başlangıç: 14:44)

Yüzlerce kopyası çalışan aynı betik, sunucunun tüm dosya tanıtıcılarını (file descriptors), bellek soketlerini ve işlemci kuyruklarını bir parazit gibi kurutmuştur.

Yönetici killall -9 php yapar; sunucu bir an nefes alır, ancak 60 saniye sonra cron tekrar çalışır ve kabus kaldığı yerden yeniden başlar!


Nerede Hata Yapıldı? İki Ölümcül İhmal

Bu felaketin iki temel sorumlusu vardır:

  1. Kod Düzeyinde Timeout Olmaması:
    cURL veya HTTP istemcisine açık bir bağlantı ve okuma zaman aşımı (Connection & Read Timeout) verilmemiştir. cURL varsayılan olarak sunucu yanıt vermezse sonsuza kadar bekleyebilir!
    // İHMAL EDİLEN HAYATİ PARAMETRELER:
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // En fazla 10 sn bağlanmayı dene
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);        // En fazla 30 sn veri bekle
  2. Sistem Düzeyinde Tekillik (Mutex / Lock) Olmaması:
    Cron zamanlayıcısı önceki görevin bitip bitmediğini kontrol etmez; körü körüne yeni süreç açar.

Cerrahi Tedavi: flock ve timeout Zırhı

Bir sistem mühendisi crontab'a bir betik eklerken işletim sisteminin sunduğu iki hayati aracı mutlaka kullanmak zorundadır: flock ve timeout.

1. flock ile Süreç Kilitleme (Asla Çift Çalıştırma!)

flock (File Lock), bir betik çalışırken geçici bir kilit dosyası tutar. Eğer önceki betik hala çalışıyorsa, ikinci betik SESSİZCE ÇALIŞMADAN ÇIKAR (Exit).

# HATALI CRON:
* * * * * /usr/bin/php /var/www/site/sync.php
 
# KUSURSUZ VE GÜVENLİ CRON (flock ile):
* * * * * /usr/bin/flock -n /tmp/sync.lock /usr/bin/php /var/www/site/sync.php

-n (non-blocking) bayrağı şunu emreder:
"Eğer /tmp/sync.lock dosyası kilitliyse (yani önceki dakika başlayan işlem henüz bitmediyse), sakın yeni bir işlem açma! Bu dakikayı atla ve hemen çık!"

Bu tek bir komut, sunucunuzda aynı anda 2 tane bile sync.php çalışmasını fiziksel olarak imkansız kılar!


2. timeout ile Zorunlu İnfaz (Sonsuza Kadar Bekleme!)

Eğer betiğiniz bir şekilde donup kalırsa, o kilidi sonsuza kadar tutmasını da engellemeniz gerekir. Bunun için Linux'un yerleşik timeout aracı devreye sokulur:

# ALTIN REÇETE: flock + timeout Kombinasyonu!
* * * * * /usr/bin/flock -n /tmp/sync.lock /usr/bin/timeout 50s /usr/bin/php /var/www/site/sync.php

Bu kuralın anlamı cerrahi bir emirdir:

  1. Önceki işlem çalışıyorsa yenisini AÇMA (flock).
  2. Eğer bu işlem 50 saniye içinde kendi kendine bitemezse, işletim sistemi bu sürece SIGKILL atıp BOĞAZINI SIKARAK ÖLDÜRSÜN (timeout 50s)!
  3. Böylece bir sonraki dakika (60. saniye) geldiğinde kilit dosyası tertemiz serbest kalır ve yeni işlem taze bir nefesle başlar.

Kurumsal Mimari: Cron Yerine Mesaj Kuyrukları (RabbitMQ / Redis)

Yüksek hacimli ve kurumsal projelerde periyodik görevlerin doğrudan crontab üzerinden koşturulması zaten arkaik (eski) bir yaklaşımdır.

Modern mikroservis mimarisinde:

  • Arka plan işleri RabbitMQ, Redis Queue (BullMQ / Celery) veya Amazon SQS gibi kuyruk yöneticilerine atılır.
  • Arka planda çalışan sınırlı sayıdaki işçi (Worker) süreçleri kuyruktan işleri sırayla çeker ve işler.
  • Kuyrukta 1 milyon iş birikse bile sunucuda 1 milyon işlem açılmaz; sadece belirlenmiş 4 adet işçi sakince görevini yapar. Sunucu asla kilitlenemez.

Sonuç

Önceki ilacın emildiğini kontrol etmeden hastanın damarına her dakika yeni enjektör boşaltan hekim hastayı öldürür; kilit ve zaman aşımı mekanizması koymadan crontab'a kontrolsüz betik ekleyen geliştirici de sunucusunu intihara sürükler.

Otomasyon kendi kendini denetleyen sınırlar koyduğunuzda bir güçtür; sınır koymadığınızda ise kendi kendini yok eden bir canavardır. Crontab'ınıza yazdığınız her satıra bir cerrah dikkatiyle bakın: flock ile kapıyı tutun, timeout ile neşterin süresini sınırlayın; sunucunuzun kendi ürettiği işlemlerin altında boğulmasına asla izin vermeyin.