systemd Timer mı Cron mu? Zamanlanmış Görevler İçin Karşılaştırma ve Örnekler
Cron onlarca yıldır işini görüyor, ama systemd timer günlük kaydı, kaçırılan çalıştırmayı telafi etme ve bağımlılık yönetimi gibi alanlarda öne çıkıyor. İkisini örneklerle karşılaştırıyoruz.
Linux'ta bir işi belirli saatte çalıştırmak için iki yaygın yol vardır: cron ve systemd timer. Cron daha eski ve daha kısadır; timer ise biraz daha fazla yazı gerektirir ama karşılığında önemli özellikler sunar. Hangisini ne zaman seçeceğinizi bilmek, "gece yedeği sessizce çalışmıyormuş" türü sürprizleri azaltır.
Cron'un kısa tarifi
crontab -e ile her satıra beş zaman alanı ve bir komut yazılır:
15 3 * * * /usr/local/bin/db-yedek.sh
Anlamı: her gün 03:15'te çalıştır. Alanlar sırasıyla dakika, saat, ayın günü, ay ve haftanın günüdür. Basit ve herkesin bildiği bir sözdizimidir.
Cron'un zayıf yönleri
- Çıktı kaybolur. Cron çıktıyı varsayılan olarak yerel posta kutusuna göndermeye çalışır; çoğu sunucuda posta sistemi yoktur ve hata mesajı sessizce yok olur. Çözüm için her satırın sonuna
>> /var/log/is.log 2>&1yazmak gerekir. - Kaçırılan çalıştırma telafi edilmez. Cihaz 03:15'te kapalıysa o gün yedek alınmaz. Raspberry Pi gibi elektrik kesintisine açık cihazlarda bu gerçek bir risktir (
anacronbu boşluğu doldurur ama ayrı kurulumdur). - Ortam farklıdır. Cron'un
PATHdeğişkeni kısıtlıdır. Elle çalışan komut, cron'da "komut bulunamadı" verebilir. - Bağımlılık yoktur. "Ağ gelsin, veritabanı hazır olsun, sonra çalış" diyemezsiniz.
systemd timer'ın iki parçası
Timer, iki dosyadan oluşur: işi tanımlayan .service ve zamanı tanımlayan .timer.
# /etc/systemd/system/rapor.service
[Unit]
Description=Gunluk rapor
After=network-online.target
[Service]
Type=oneshot
User=pi
ExecStart=/usr/bin/python3 /home/pi/rapor.py
# /etc/systemd/system/rapor.timer
[Unit]
Description=Her sabah rapor
[Timer]
OnCalendar=*-*-* 08:00:00
Persistent=true
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now rapor.timer
Timer'ın üstün yönleri
Günlük kaydı hazırdır. Çıktı ve hata mesajları otomatik olarak journal'a düşer: journalctl -u rapor.service. Son çalıştırmanın ne zaman olduğunu systemctl list-timers gösterir.
Persistent=true kaçırılanı telafi eder. Cihaz kapalıyken geçen zamanlama, açıldığında hemen çalıştırılır.
Bağımlılık ve ortam tanımlanabilir. After=, Requires=, EnvironmentFile= ve User= ile işin hangi koşulda ve hangi kullanıcıyla çalışacağı açıkça yazılır.
Sınırlama getirilebilir. TimeoutStartSec=, MemoryMax=, Nice= gibi ayarlarla kontrolden çıkan bir işin sistemi boğması önlenir.
Elle tetiklenebilir. Beklemeden denemek için sudo systemctl start rapor.service yeterlidir. Test için saati değiştirmenize gerek kalmaz.
OnCalendar ifadeleri
Timer'ın zaman sözdizimi okunaklıdır:
| İfade | Anlamı |
|---|---|
daily |
Her gün 00:00 |
*-*-* 08:00:00 |
Her gün 08:00 |
Mon..Fri 09:00 |
Hafta içi 09:00 |
*:0/2 |
Her 2 dakikada bir |
*-*-01 04:00:00 |
Her ayın 1'i 04:00 |
Sun *-*-* 02:30 |
Her pazar 02:30 |
İfadeyi yazmadan önce doğrulamak için şu komutu kullanın; bir sonraki çalışma zamanını gösterir:
systemd-analyze calendar "Mon..Fri 09:00"
Aralıklı ve sık çalışan işler için (ör. 2 dakikada bir kontrol) OnUnitActiveSec=2min ve OnBootSec=1min birlikte kullanılabilir.
Hangisi ne zaman?
- Cron seçin: Tek satırlık, önemsiz, hata olursa kaybolması sorun olmayan işler; çok eski sistemler; hızlı denemeler.
- Timer seçin: Yedekleme, rapor, e-posta, alarm gibi sonucu önemli olan işler; kapanıp açılabilen cihazlar; günlük kaydı gereken her şey.
Basit bir kural: işin başarısız olduğunu bilmek sizin için önemliyse timer kullanın.
Cron'dan geçiş
Mevcut bir cron satırını timer'a çevirmek için komutu ExecStart= satırına, zamanı OnCalendar= satırına taşımanız yeterlidir. ExecStart içinde komutun tam yolunu yazın; PATH'e güvenmeyin. Geçişi doğruladıktan sonra cron satırını silmeyi unutmayın, aksi halde iş iki kez çalışır.
İlgili örnek: MariaDB otomatik yedekleme yazımızda gece yedeği için timer kurulumunu uygulamalı olarak görebilirsiniz.
Uygulamalı örnek: gece yedeği için timer yazmak
Elimizde /usr/local/bin/gece-yedek.sh adında bir betik olsun. Önce servis birimi, ardından zamanlayıcı yazılır. Servis dosyası (/etc/systemd/system/gece-yedek.service):
[Unit]
Description=Gece veritabani yedegi
[Service]
Type=oneshot
ExecStart=/usr/local/bin/gece-yedek.sh
Zamanlayıcı dosyası (/etc/systemd/system/gece-yedek.timer):
[Unit]
Description=Gece yedegini her gun 02:30'da calistir
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=120
[Install]
WantedBy=timers.target
Etkinleştirmek için sudo systemctl daemon-reload ve ardından sudo systemctl enable --now gece-yedek.timer komutları çalıştırılır. Persistent=true sayesinde cihaz gece kapalıysa, açıldığında kaçan çalışma telafi edilir; cron'da bu davranış yoktur. RandomizedDelaySec ise aynı anda birçok görevin başlamasını önlemek için küçük bir rastgele gecikme ekler.
Zamanlayıcıyı doğrulamak ve sorun gidermek
Kurulumdan sonra üç komut size gerçeği söyler:
systemctl list-timers— tüm zamanlayıcıları, sonraki ve son çalışma zamanlarıyla listeler. Sizin timer'ınız listede yoksa etkinleştirilmemiştir.systemctl status gece-yedek.service— son çalışmanın başarılı olup olmadığını gösterir.journalctl -u gece-yedek.service -n 50— betiğin çıktısını ve hatalarını gösterir (bkz. journalctl ile log okuma).
Zamanlama ifadesini denemek için systemd-analyze calendar "*-*-* 02:30:00" komutunu kullanın; sonraki çalışma zamanını yazdırır. Cron ifadelerinin ne zaman çalışacağını görmek için ise cron ifadesi oluşturucu aracını kullanabilirsiniz.
Sık karşılaşılan hatalar: birim dosyası değiştirildikten sonra daemon-reload unutulması (eski ayar çalışmaya devam eder), betiğin çalıştırma izninin olmaması (chmod +x), betikte tam yol yerine kısa komut adı kullanılması ve timer'ın etkinleştirilip servisin değil timer'ın başlatılması gerektiğinin karıştırılması. Servis dosyasına [Install] bölümü yazmanız gerekmez; etkinleştirilen şey timer'dır.
Sık sorulan sorular
Cron'u tamamen bırakmalı mıyım? Hayır. Kısa, tek satırlık ve taşınabilir görevlerde cron hâlâ pratiktir. Birden fazla sunucuda aynı crontab'ı kullanıyorsanız ya da sistem systemd kullanmıyorsa cron'da kalmak mantıklıdır.
Birden fazla zaman vermek mümkün mü? Evet; birden çok OnCalendar= satırı ekleyebilirsiniz, örneğin hafta içi 09:00 ve hafta sonu 11:00.
Görev uzun sürerse ikinci çalışma üst üste biner mi? Aynı servis zaten çalışıyorsa systemd ikinci bir kopya başlatmaz; cron'da ise bu sizin flock gibi bir kilit kullanmanıza bağlıdır.
Hata olursa haber nasıl alırım? Servise OnFailure= tanımlayıp bir bildirim servisini çağırabilirsiniz; yaklaşımı servis izleme ve alarm rehberinde anlattık.