Cron Olmayan Hostingde Zamanlanmış Görev: Tembel Cron Mimarisi

Cron Olmayan Hostingde Zamanlanmış Görev: Tembel Cron Mimarisi

Kısa cevap: Paylaşımlı hostingde cron erişiminiz yoksa zamanlanmış işlerinizi ziyaretçi isteklerine bindirebilirsiniz. Buna tembel cron denir: her sayfa isteğinin sonunda, çıktı tarayıcıya gönderildikten sonra bir kontrol çalışır, vakti gelen görev varsa arka planda tetiklenir. Doğru kurulduğunda sayfa hızını hiç etkilemez; yanlış kurulduğunda ise aynı görevi aynı anda beş kez çalıştırıp veritabanınızı kilitler. Farkı yaratan üç şey vardır: çıktıdan sonra çalıştırma, kilit dosyası ve son çalışma zamanı takibi.

Kısaca: 60 saniyede özet

  • Tembel cron, zamanlanmış görevi ziyaretçi trafiğinin tetiklemesidir.
  • Görev mutlaka çıktı gönderildikten sonra çalışmalı; aksi halde o ziyaretçi 8 saniye bekler.
  • Kilit dosyası olmadan eş zamanlı istekler aynı görevi tekrar tekrar başlatır.
  • Son çalışma zamanını veritabanında tutun, dosya değil satır güvenilirdir.
  • Trafiği düşük siteler için harici bir tetikleyici, örneğin uptime izleme servisi, şart.
  • Kesin saatte çalışması gereken işler tembel cron ile yapılmaz; yaklaşık zamanlama kabul edilebilir işler için uygundur.

Tembel cron nedir?

Klasik cron, işletim sistemi seviyesinde çalışan bir zamanlayıcıdır. Sunucu, siz uyurken bile belirlediğiniz dakikada betiğinizi çağırır. Ancak birçok paylaşımlı hosting paketinde cron ya hiç yoktur, ya en fazla saatte bir çalışacak şekilde sınırlandırılmıştır ya da panelde bulunmasına rağmen PHP ikili dosyasının yolunu tutturmak ayrı bir uğraştır.

Tembel cron bu sorunu tersten çözer. Zamanlayıcı yoktur; onun yerine siteye gelen her istek bir saat vuruşu gibi kullanılır. Ziyaretçi ana sayfayı açar, sayfa normal şekilde render edilir ve kullanıcıya gönderilir. Bağlantı kapandıktan sonra PHP hâlâ arka planda çalışmaya devam eder; işte bu boşlukta bekleyen görevler kontrol edilir. Ziyaretçi bunu hiç fark etmez.

Gerçek cron ile tembel cron arasındaki fark ne?

Kriter Gerçek cron Tembel cron
Zamanlama hassasiyeti Dakika hassasiyetinde Yaklaşık, trafiğe bağlı
Trafik gereksinimi Yok Var, ziyaretçi olmazsa çalışmaz
Sunucu erişimi Panel veya SSH gerekir Gerekmez, sadece PHP yeterli
Taşınabilirlik Sunucuya bağımlı, taşınırken unutulur Kod ile birlikte taşınır
Uygun işler Yedekleme, gece raporu, fatura kesimi Önbellek tazeleme, veri çekme, kuyruk işleme, temizlik

Bu tablodan çıkan pratik sonuç şu: tembel cron bir alternatif değil, bir yedek plandır. Cron erişiminiz varsa onu kullanın; olmadığında ya da projeyi başkasının sunucusuna teslim edecekseniz tembel cron sizi kurulum talimatı yazmaktan kurtarır.

Tembel cron nasıl kurulur?

1. Görev tablosunu oluşturun

Son çalışma zamanını dosyaya yazmak kolay görünür ama takip edilebilirliği zayıftır. SQLite tarafında küçük bir tablo, hangi görevin ne zaman çalıştığını ve hata verip vermediğini görmenizi sağlar:

CREATE TABLE IF NOT EXISTS cron_gorevleri (
  id            INTEGER PRIMARY KEY AUTOINCREMENT,
  anahtar       TEXT UNIQUE NOT NULL,
  aralik_saniye INTEGER NOT NULL,
  son_calisma   INTEGER DEFAULT 0,
  son_sure_ms   INTEGER DEFAULT 0,
  son_durum     TEXT DEFAULT '',
  aktif         INTEGER DEFAULT 1
);

2. Tetikleyiciyi sayfanın en sonuna koyun

Kritik nokta burasıdır. Görevi doğrudan çağırırsanız o isteği yapan ziyaretçi işin bitmesini bekler. Çözüm, bağlantıyı kapatıp arka planda devam etmek:

<?php
function tembel_cron_tetikle(): void
{
    ignore_user_abort(true);
    set_time_limit(120);

    // PHP-FPM ortamında ziyaretçiye cevabı hemen kapat
    if (function_exists('fastcgi_finish_request')) {
        fastcgi_finish_request();
    } else {
        // Apache mod_php icin manuel kapatma
        if (ob_get_level() > 0) {
            ob_end_flush();
        }
        flush();
    }

    tembel_cron_calistir();
}

Bu fonksiyonu şablonunuzun en son satırında, kapanış etiketlerinden sonra çağırın. Böylece görev ne kadar sürerse sürsün ziyaretçinin sayfası çoktan yüklenmiş olur.

3. Kilit dosyası ile eş zamanlı çalışmayı engelleyin

Aynı saniyede beş ziyaretçi geldiğinde beş ayrı süreç aynı görevi başlatmaya çalışır. Bunu engellemenin en sağlam yolu, bloklamayan bir dosya kilididir:

function tembel_cron_calistir(): void
{
    $kilitYolu = sys_get_temp_dir() . '/tembel_cron_' . md5(__DIR__) . '.lock';
    $kilit = fopen($kilitYolu, 'c');
    if (!$kilit) {
        return;
    }

    // LOCK_NB: kilit meshgulse bekleme, sessizce cik
    if (!flock($kilit, LOCK_EX | LOCK_NB)) {
        fclose($kilit);
        return;
    }

    try {
        $simdi = time();
        $db = veritabani();
        $gorevler = $db->query(
            'SELECT * FROM cron_gorevleri WHERE aktif = 1'
        )->fetchAll(PDO::FETCH_ASSOC);

        foreach ($gorevler as $gorev) {
            if ($simdi - (int)$gorev['son_calisma'] < (int)$gorev['aralik_saniye']) {
                continue;
            }
            gorev_yurut($db, $gorev, $simdi);
        }
    } finally {
        flock($kilit, LOCK_UN);
        fclose($kilit);
    }
}

Buradaki LOCK_NB bayrağı çok önemlidir. Onu koymazsanız süreçler kilidin açılmasını bekler, PHP işçileri birikir ve site yavaşlar. Bloklamayan kilit ise ikinci süreci hiç bekletmeden geri gönderir.

4. Görevi çalıştırın ve sonucu kaydedin

Zaman damgasını görev başlamadan önce güncellemek, uzun süren bir görev çakılsa bile aynı işin dakikalarca tekrar tekrar denenmesini önler:

function gorev_yurut(PDO $db, array $gorev, int $simdi): void
{
    // Once damgayi guncelle, sonra calistir
    $db->prepare('UPDATE cron_gorevleri SET son_calisma = ? WHERE id = ?')
       ->execute([$simdi, $gorev['id']]);

    $baslangic = microtime(true);
    $durum = 'ok';

    try {
        match ($gorev['anahtar']) {
            'onbellek_tazele'  => onbellek_tazele(),
            'kuyruk_isle'      => kuyruk_isle(50),
            'gunluk_temizlik'  => eski_kayitlari_sil(30),
            default            => null,
        };
    } catch (Throwable $e) {
        $durum = 'hata: ' . mb_substr($e->getMessage(), 0, 180);
        error_log('[tembel-cron] ' . $gorev['anahtar'] . ' - ' . $e->getMessage());
    }

    $sure = (int)round((microtime(true) - $baslangic) * 1000);
    $db->prepare('UPDATE cron_gorevleri SET son_sure_ms = ?, son_durum = ? WHERE id = ?')
       ->execute([$sure, $durum, $gorev['id']]);
}

Bir turda birden fazla görevin vakti gelmişse hepsini aynı istekte çalıştırmak yerine yalnızca birini alıp çıkmak da makul bir tercihtir. Böylece tek bir ziyaretçi isteğine ağır bir yük binmez, görevler sıraya girer.

Trafiği olmayan sitede tembel cron nasıl çalışır?

Tembel cronun tek gerçek zayıflığı budur: ziyaretçi yoksa saat durur. Gece boyunca hiç trafik almayan bir site, sabah ilk ziyaretçi geldiğinde bütün bekleyen işleri aynı anda yapmaya kalkar. Üç pratik çözüm var:

  1. Uptime izleme servisini tetikleyici olarak kullanın. Zaten sitenizi beş dakikada bir kontrol eden bir izleme aracınız varsa, onu tembel cron uç noktanıza yönlendirin. Ben kendi projelerimde bu işi Nabız adını verdiğim kendi izleme sistemim ile yapıyorum; hem site ayakta mı diye bakıyor hem de görevleri tetikliyor.
  2. Ücretsiz harici ping servisleri. Belirli aralıkta bir adrese istek atan servisler işi çözer, ancak uç noktayı gizli bir anahtar ile korumayı ihmal etmeyin.
  3. Birbirini tetikleyen projeler. Aynı sunucuda birden fazla siteniz varsa, trafiği yüksek olanın tembel cronu diğerlerinin uç noktasını da uyandırabilir.

Tembel cronda en sık yapılan dört hata

  • Görevi çıktı gönderilmeden çalıştırmak. Sayfa hızı raporlarında sebebi anlaşılmayan yavaş istekler görüyorsanız ilk buraya bakın.
  • Zaman damgasını görev bittikten sonra yazmak. Görev hata verirse damga hiç güncellenmez ve her istekte yeniden denenir; hatalı bir veri çekme işi böylece hedef siteye saldırı gibi görünmeye başlar.
  • Kilidi bloklamalı kullanmak. LOCK_NB olmadan kilit beklemeye dönüşür, PHP işçi havuzu dolar.
  • Ağır işleri tek parça yapmak. Beş bin kaydı tek turda işlemek yerine her turda elli kayıt işleyip kuyruğu ilerletmek, hem zaman aşımını hem de bellek sorunlarını ortadan kaldırır.

Saha notu: Neden artık her projeye bunu koyuyorum

Projeleri müşteriye teslim ederken en çok geri dönen soru cron kurulumuydu. Hosting paneli her sağlayıcıda farklı, PHP yolunu bulmak ayrı bir mesele, üstelik müşteri siteyi başka bir sunucuya taşıdığında cron arkada kalıyor ve haftalar sonra veriler güncellenmiyor diye telefon geliyordu. Tembel cronun asıl kazancı hız değil, kurulum talimatı gerektirmemesi. Dosyaları yükleyince sistem kendi kendine tıklamaya başlıyor.

İkinci kazanç görünürlük oldu. Görev tablosuna son çalışma, süre ve durum sütunları koyduğumda yönetim paneline küçük bir ekran ekleyip hangi işin ne kadar sürdüğünü görebildim. Klasik cron ile bu bilgi sunucu günlüklerinde kayboluyordu; şimdi 4 saniyeye çıkan bir görevi aynı gün fark ediyorum.

Sık Sorulan Sorular

Tembel cron sayfa hızını düşürür mü?

Doğru kurulduğunda düşürmez. Görev, çıktı ziyaretçiye gönderildikten sonra çalıştığı için tarayıcı tarafında ölçülen süreye eklenmez. Sunucu kaynağı elbette harcanır, bu yüzden ağır işleri parçalara bölmek gerekir.

Kesin saatte çalışması gereken işlerde kullanılabilir mi?

Kullanılmamalı. Gece yarısı kapanış raporu, ay sonu faturalama gibi tam saat gerektiren işler gerçek cron ister. Tembel cron, aralık bazlı yani her 15 dakikada bir gibi tanımlanan işler için uygundur.

Aynı görev iki kez çalışırsa ne olur?

Kilit ve zaman damgası doğru kurulduğunda bu ihtimal büyük ölçüde ortadan kalkar. Yine de görevlerinizi tekrar çalıştırmaya dayanıklı yazın: veri eklerken benzersiz anahtar kullanın, sayaç artırmak yerine yeniden hesaplayın.

SQLite kilitleniyor, ne yapmalıyım?

WAL modunu açın ve meşgul bekleme süresi tanımlayın. Bu iki ayar, okuma yapan ziyaretçiler ile yazma yapan görevin birbirini bloklamasını büyük oranda çözer:

$db->exec('PRAGMA journal_mode = WAL');
$db->exec('PRAGMA busy_timeout = 5000');

Görevleri harici uç nokta ile tetiklerken güvenlik nasıl sağlanır?

Uç noktaya tahmin edilemez bir anahtar parametresi ekleyin ve anahtar eşleşmezse 404 döndürün. Ayrıca uç noktayı sitemap ve robots dosyalarına koymayın, arama motorlarının keşfetmesi için sebep bırakmayın.

Bir görevin hiç çalışmadığını nasıl anlarım?

Görev tablosundaki son çalışma sütununu yönetim panelinde gösterin ve beklenen aralığın iki katını aşan satırları renklendirin. Sessiz kalan bir zamanlanmış görev, hata veren bir görevden daha tehlikelidir.

T

Ramazan YEŞİLDAL

Merhaba! Ben Ramazan, Bir yazılım geliştiricisiyim.

💬 Yorumlar (0)

İlk yorumu siz yapın!

💬 Yorum Yap