Şeytan, Pengueni Dürterse

March 28, 2010

Günümüzde birçok site arkada yapılacak görevleri çalıştırmak için görev yöneticileri kullanılır. Crontab (Zaman ayarlı) ve Daemon (kendi halinde çalışan) iki görev yöneticinin arasındaki bence tek fark (durum bu kadar basit olmasada) Crontab'ın 1 dakikanın altındaki süreçlere göre çalışmamasıdır. Bu görevler için Daemon denilen ve /etc/init.d altında tetiklenen ve sinyallerle çalıştırılıp durdurulabilen ve process id değeri üreten bir teknolojiye ihtiyaç duymasıdır. Daemon'lar init.d altında bir çalıştırıcı scripte sahip olmaya bilir ama durdumak istendiğinde güç kullanılarak öldürülmesi (kill)  gerekir ki, kritik işlerde bu pek tehlikeli bir yöntemdir. Init.d altındaki başlatma scripti bir proses(PID) dosya yaratır ve daemon'u çalıştırır. Sonrasında durdumak isterse daemon'a sinyal gönderir. Böylece uygulama durma sinyalini görünce düzgün bir şekilde sonlanır. Crontab ise belli bir işin bellir bir saatte yapılmasını sağlar. Saatte bir, her 15 dk.'da bir ayın 5. günü, her çarşamba saat 15'te gibi...

Kullanım alanlarına birkaç örnek vermek gerekirse;

Daemon; Özellikle kuyruktaki işleri işlemek için çok kullanılır.

Cron;

Daemon yazmak genelde C dili ile yazılan işlerdendir. Çünkü bu iş hem performans hem de sistem programlama(sinyaller ve prosesler) bilgisi  gerekir. Buna rağmen, işin mantığı ise  PHP, ve benzeri web dillerinde yazılmıştır. Belki de biraz bu sebeplerle Crontab ile görev tanımı yapılır. Crontab kullanmak güzeldir ama kurulum sürecinde ek yük getirir. Bunların doğru bir şekilde çalıştığının kaydının tutulması (loging) ve gözlenmesi (monitoring) işlerinin yapılmasıda cabası.

Bu yazı Chronical projesinin bilgi tasarımının ilk taslaklarını içermesinin yanında aktif olan mevcut uygulamalardan örnekler de verilecektir.

Peki bu işleri ne şekilde yapımak gerekir?

1) System_Daemon PEAR Paketi

PEAR kütüphanesi içerisinde bulunan ve Kevin van Zonneveld tarafından geliştirilen System_Daemon paketi kolayca linux daemonları yaratmanıza olanak verecek olan harika bir araçtır. Becerileri;

  1. İşletim sistemine özel başlangıç ayarlarının ve kurulumlarının kolayca yapılabilmesi.
  2. İşlem kaydı (loging) tutalbilmesi. Ve PEAR kütüphanesi ile uyumluluk
  3. Kullanım kolaylığı, birazdan örnek uygulamada da görebileceksiniz
  4. Sinyallerle çalışma ve özelleştirme
System Daemon Kurulum; Linux sunucunuzda PEAR kurulu ise şu şekilde;
$ pear install -f System_Daemon
Yada şuradan indirerek kullanabilirsiniz. Kullanım; job/sms_sender.php isimli bir php dosyası yaratalım.
// Gerekli olan Daemon kütüphanesi.
// Bu kütüphane include_dir dizininin gösterdiği bir yerde olmalı.
require_once "System/Daemon.php";

// İzin verilen parametreler
$runmode = Array (
    // tek başına çalışması için
    'standalone' => false,
    // initd dizininde çalıştırma betiği yaratır.
    'write-initd' => false,
);

// Scan command line attributes for allowed arguments
foreach ($argv as $k=>$arg) {
    if (substr($arg, 0, 2) == '--' && isset($runmode[substr($arg, 2)])) {
        $runmode[substr($arg, 2)] = true;
    }
}

// appName minimum gerekli olan parametredir.
System_Daemon::setOption("appName", "sms_sender");

// System_Daemon::setOption ile tek tek  ya da
// System_Daemon::setOptions($options) ile toplu olarak girilebilir.

$options = array(
    //'appName' => 'sms_sender',
    'appDir' => dirname(__FILE__),
    'appDescription' => 'MT SMS Sender',
    'authorName' => 'Hasan Ozgan',
    'authorEmail' => 'hasan@ozgan.net',
    'sysMaxExecutionTime' => '0',
    'sysMaxInputTime' => '0',
    'sysMemoryLimit' => '1024M',
    'appRunAsGID' => 1000,
    'appRunAsUID' => 1000,
);
System_Daemon::setOptions($options);

// Eger daemon olarak çalışmayacaksa
// System_Daemon::start() methodu ile başlatılabilir.
if ($runmode["standalone"]) {
    System_Daemon::start();
}

// job --write-initd parametresi ile çalıştırıldığında kendini kaydeder.
// açılışta çalıştırıldığında ise --init.d parametresi alır.
if (!$runmode["write-initd"]) {
     System_Daemon::info('not writing an init.d script this time');
} else {
    if (($initd_location = System_Daemon::writeAutoRun()) === false) {
        System_Daemon::notice('unable to write init.d script');
    } else {
        // parametreli log örneği...
        System_Daemon::info(
            'sucessfully written startup script: %s',
            $initd_location
        );
    }
}

// Daemon stop sinyali gelene kadar çalışmaya devam eder.
while (!System_Daemon::isDying()) {
   // Buraya işinizle ilgili kodları eklemelisiniz.

   $messages = OutgoingSMS::fetchMessages();
   foreach ($messages as $message) {
       if (!$message->send()) {
            System_Daemon::error("Message not send");
       }
   }

   // Daemonlarda önemli olan sonsuz döngüde bir miktar
   // işlem yapıp sistemi dinlendirmek gerekir.
   // Bunun için ise iterate methodu ile saniye cinsinden
   // bir süre vererek çağrı yapmak gerekir.
   System_Daemon::iterate(5);
}

System_Daemon::stop();

Yazdığımız scripti tek başına çalıştırmak için ise;

$ job/send_sms --standalone
yazmamız yeterlidir. Service birkez çalışıp sonlanacaktır.

Servisimizi init.d altına kaydetmek için ise;

$ sudo job/send_sms --write-initd
yazmamız yeterlidir. Eğer burada hata alırsanız, init.d dizinin yazma haklarını kontrol etmeniz gerekir.
$ sudo chmod a+w /etc/init.d

Bu işlemleri yaptıktan sonra appName parametresinde girdiğimiz isme göre; dosyaları oluşturulur. İşletim sisteminin açılışta servisi çalıştırması için kayıt etmek gerekir.
# kayıt için
$ sudo update-rc.d send_sms defaults
# kaldırmak için ise
$ sudo update-rc.d -f send_sms remove

2) Periodic Kütüphanesi

Arbit firması tarafından geliştirilen Periodic kütüphanesini kullanabilirsiniz. Bu kütüphane crontab işlerini kendi sarmalayan biraz daha karmaşık bir mimariye sahiptir.


 
  
     92384032
     92384032
  
  
     
  </command>
  
     
  </command>
  

Periodic ile ilgili daha detaylı bilgiyi şuradan alabilirsiniz.

3) Chronical Job Management Projesi</strong</p>

Bu proje benim yapacağım hem cron hem de daemon desteği ile melez çalışacak bir projedir. Henüz fikir halindedir. Projene adresine şuradan ulaşılabilir.

Bu proje servis işlerinizi hızlı ve kolay bir şekilde merkezi bir yerden yönetmeniz, durumunu kontrol etmenizi amaçlar.

Özellikleri

Örnek proje ayar dosyası (task.config);

# Period Format
# second minute hour day month dayOfWeek weekOfMonth
# second: 0-59
# minute: 0-59
# hour: 0-23
# day: 1-31
# month: 1-12
# dayOfWeek: 1-7
# weekOfMonth: 1-5

# proje adina göre tek bir daemon oluşur.
# Bu daemon işlerin tamamını alt prosesler yaratarak yönetir.

proje_adi:
    gorev_adi:
        class: Application_Jobs_SmsSender
        # her 30 saniyede bir çalış anlamında.
        period: */30 * * * * *
    change_theme:
        class: Application_Jobs_ChangeTheme
        # Mayıs ayının ikinci pazar günü saat gece 2'de
        # Anneler gününde çalış.
        period: * 2 * 5 7 2

Arayüz Sınıfı

interface Chronical_Job_Interface
{
     // Ayar dosyasına verilen sınıfların bu
     // arayüzden gerçekleştirilmesi gerekir.
     public function run();
}

Örnek Sınıfı

class Application_Jobs_SendSms
                    extends Joy_Application
                    implements Chronical_Job_Interface
{
     public function run()
     {
           // TODO: Yapılacak işler....
     }
}

Örnek log ayar dosyası; Bu dosya chronical uygulamasının log ve pid ayarları ile ilgili bir dosyadır. Ubuntu ve debian temelli dağıtımlar için /etc/chronical.ini

[folders]
     folder.log = /var/log/
     fodler.pid = /var/run/
     folder.init.d = /etc/init.d
[defaults]
; seconds
     default.sleep_time = 5

Düşünülen betik dosyası örnek işler

# OS startup install for init.d
$ chronical install task.config

# OS startup uninstall for init.d
$ chronical uninstall task.config

# Görev çalıştırma
$ chronical start proje_adi:gorev_adi

# Görev durdurma
$ chronical start proje_adi:gorev_adi

# Görev durumunu görme
$ chronical status proje_adi:gorev_adi
Kısaca Unix sistemleri üzerinde daemon ve crontab işleri bu şekilde. (: