- systemd zamanlayıcıları,
cron için pratik bir alternatif olup programa göre .service gibi üniteleri çalıştırır ve geçmiş, çıktı ile ortam yönetimini daha açık hale getirir
- Geleneksel
cron, belirsiz $PATH, kolayca kaybolabilen stdout/stderr, izlenmesi zor çalışma geçmişi ve okunması güç zamanlama sözdizimi gibi zayıf yönlere sahiptir
- Zamanlayıcılar aynı köke sahip
.timer ve .service dosyalarını bağlar; OnCalendar, OnBootSec, OnUnitActiveSec ile saat ve olay tabanlı çalıştırmayı ifade eder
systemd-analyze calendar ve systemctl list-timers ile zaman ifadeleri ve bir sonraki çalışma zamanı kontrol edilebilir; WakeSystem= ise askı durumundayken bile sistemi uyandırıp çalıştırabilir
RandomizedOffsetSec ve FixedRandomDelay= eşzamanlı çalışma zirvelerini azaltır; Persistent= ise devre dışı kalınan sürede kaçırılan çalıştırmaları sistem yeniden çevrimiçi olur olmaz telafi eder
cron yerine neden systemd zamanlayıcısı kullanılmalı
cron job, gerçek cron arka plan süreci olmasa bile “bunu her gün çalıştır”, “şunu her ay çalıştır” gibi takvime göre işleri yürüten temel bir bilişim yapıtaşını anlatmak için yaygın biçimde kullanılır
- systemd zamanlayıcısı, belirli bir programa göre başka bir systemd ünitesini, genellikle bir
.service ünitesini çalıştıran bir systemd ünitesidir ve geleneksel cron arka plan sürecinin işlevsel yerine geçebilir
- Geleneksel
cronun pratikte bazı zayıf yönleri vardır
- Belirsiz
$PATH ayarı yüzünden betiklerin nasıl çalışacağını öngörmek zordur
stdout ve stderr çıktıları sık sık bir kara deliğe gider ya da makinenin posta sistemine gönderilir
- Çalışma geçmişini izlemek ve sorgulamak zordur
01,31 04,05 1-15 1,6 * gibi zamanlama sözdizimi insanlar için ne kolay okunur ne de sezgiseldir
- systemd zamanlayıcıları bu sorunları azaltırken
cron tarzı ifadelere benzeyen takvim yapılandırmaları da sunar
Temel yapı: servis ve zamanlayıcı
- systemd zamanlayıcılarının çalıştıracağı bir hedefe ihtiyacı vardır;
.service ünitesi mantıksal olarak bir betik gibi düşünülebilir
- Örneğin
/etc/systemd/system/roulette.service içine aşağıdaki üniteyi koyarsanız, bilgisayarı 10'da 1 ihtimalle kapatan bir servis kurmuş olursunuz
[Unit]
Description=1 in 10 chance to break your chains
[Service]
ExecStart=/usr/bin/env bash -c '[[ $(($RANDOM % 10)) == 0 ]] && systemctl poweroff || echo LIVE ANOTHER DAY'
ExecCondition=, koşullu çalıştırmayı systemd servis seçeneği olarak ifade etmenin daha bütünleşik bir yoludur ve “çalışmaya devam edilmeli mi?” sorusunu ünite seviyesinde daha açık gösterir
[Unit]
Description=1 in 10 chance to break your chains
[Service]
ExecCondition=/run/current-system/sw/bin/bash -c '[[ $(($RANDOM % 10)) == 0 ]]'
ExecStart=/run/current-system/sw/bin/systemctl poweroff
- Koşul sağlanmazsa günlükte daha açık bir ifade kalır
May 05 11:05:32 diesel systemd[3117]: Condition check resulted in 1 in 10 chance to break your chains being skipped.
- Genel olarak systemd'nin sunduğu seçeneklerden yararlanmak, her şeyi kendiniz betiklemeye göre daha iyi bir deneyim sağlar
OnFailure= servis betiği başarısız olduğunda tepki vermek için kullanılabilir
Restart= geçici hatalardan kurtulmayı denemek için kullanılabilir
Zamanlayıcı ünitesini bağlama ve çalıştırma
- Aynı dosya köküne sahip bir
/etc/systemd/system/roulette.timer dosyası oluşturarak zamanlayıcıyı roulette.service ile bağlayabilirsiniz
[Unit]
Description=impending destruction
[Timer]
OnCalendar=10:00
[Install]
WantedBy=timers.target
- Varsayılan olarak zamanlayıcının
Unit= ayarı, aynı köke sahip .service uzantılı servis ünitesini seçer
- Bu örnekte
roulette.service seçilir
- Farklı isimli bir servis ünitesini çalıştırmak istiyorsanız
Unit= değerini değiştirebilirsiniz
ExecStart= hedefi varsayılan olarak kabuk komutu olarak çalıştırılmaz
- Mutlak yol hedefleri, betik olarak ya da bir betiği dize argümanı olarak bekleyen yorumlayıcı gibi ele alınmalıdır
ExecStart=/usr/bin/echo Hello | /usr/bin/awk burada boru anlam taşımadığından çalışmaz
ExecStart= argümanları varsayılan olarak, bazı sistem yöneticisi varsayılanları dışında ortam değişkenlerini miras almaz
- Varsayılan
$PATH neredeyse boş sayılabilecek durumdadır
/usr/bin/env çalıştırmak, systemctl gibi öğelerin kullanılabilmesini sağlayan basit bir koruma olur
- Yalnızca
ExecStart=/usr/bin/bash kullanılsaydı $PATH içine varsayılan girdiler gelirdi, ama env kullanımı ek bir güvenlik önlemidir
- Servisi zamanlayıcı olmadan da doğrudan çalıştırabilirsiniz
systemctl start roulette
[Install] bölümü olmayan servisler enable edilemez; bu yapıda zamanlayıcı, servisi tutarlı biçimde çalıştırmanın standart yoludur
systemctl, açıkça sonek verilmemiş olsa bile varsayılan olarak roulette.service üzerinde işlem yapar
.timer ünitesine systemctl start uygulamak zamanlayıcıyı etkin duruma getirir, fakat gerçek Unit= hedef servisini hemen çalıştırmaz
systemctl start roulette.timer
status, zamanlayıcının bir sonraki ne zaman çalışacağını gösterir
systemctl status roulette.timer
Trigger: Sat 2026-04-18 10:00:00 MDT; 35min left
- En basit akış, çalıştırılacak servisi oluşturmak, aynı yerde programı olan bir zamanlayıcı tanımlamak ve hedef yerine zamanlayıcıyı başlatmaktır
- Zamanlayıcı ünitesinin
[Install] bölümünde WantedBy= varsa, açılışta da etkinleşmesi sağlanabilir
systemctl enable roulette.timer
Zaman ifadeleri: takvim olayları ve süreler
- Zamanlayıcılarda zamanın nasıl ifade edildiği önemlidir; yinelenen zaman aralıkları ile takvim olayları veya zaman damgaları arasındaki farkı ayırmak gerekir
systemd.time(7) kılavuzu bol örnek içerir ve zamanlayıcı yazarken ilk başvurulacak kaynak olmaya uygundur
systemd-analyze, zaman ifadelerini doğrulayabilir ve açıklayabilir
systemd-analyze calendar '*-*-* *:*:*'
Normalized form: *-*-* *:*:*
Next elapse: Sat 2026-04-18 16:44:26 MDT
(in UTC): Sat 2026-04-18 22:44:26 UTC
From now: 431ms left
- systemd zamanlayıcıları yalnızca yinelenen duvar saati zamanlarını değil, geleneksel
crondan farklı olarak, önceki bir olaya göre yinelenen süreleri de tanımlayabilir
daily ifadesinin tam açılımı, her yıl, her ay, her gün saat 00:00:00'da çalışmasıdır
*-*-* 00:00:00
│ │ │ │ │ ╰── at second 00
│ │ │ │ ╰───── at minute 00
│ │ │ ╰──────── at hour 00
│ │ ╰────────── every day
│ ╰──────────── every month
╰────────────── every year
daily gibi kısaltmalar, tam biçim ve systemd.time(7) içindeki diğer desteklenen değerler kullanılabilir; varsayımlarınızı systemd-analyze ile doğrulayabilirsiniz
Olay tabanlı çalıştırmanın daha uygun olduğu durumlar
- Gerçek işlerde çoğu zaman “her gün aynı saatte çalıştır” yerine “başka bir olaydan sonra çalıştır” yaklaşımı daha uygundur
- Geçici dizinleri temizleyen bir işte, açılıştan hemen sonra
cron ifadesindeki saat geçmişse /tmp içinde temizlenecek çok az şey olabilir
- “Bilgisayar açıldıktan bir saat sonra çalıştır, ardından her saat tekrar çalıştır” ifadesi, servisin gerçek davranışıyla ve zamanlama mantığıyla daha iyi örtüşür
[Timer]
OnBootSec=1h
OnUnitActiveSec=1h
OnBootSec=1h, makine açıldıktan bir saat sonra bir kez çalıştırmak anlamına gelir
OnUnitActiveSec=1h, Unit= çalıştırıldıktan bir saat sonra tekrar çalıştırmak anlamına gelir ve zamanlayıcının örtük olarak tekrar etmesini sağlar
- Bu tür periyodik süre ifadeleri, “her saatin şu dakikasında çalıştır” ifadesine göre “arada bir çalıştır” türü işler için daha sık uygundur
- Advent of Code API'sini sorgulayan Slack botu örneğinde
*/15 cron ifadesi API'nin “15 dakikada bir” kuralına uyar, ancak herkes aynı şekilde sorgularsa trafik yığılabilir
- Kod değişikliğinden sonra zamanlayıcıyı başlatıp her 15 dakika geçtiğinde çalışacak şekilde ayarlamak, gereken davranışı karşılayıp thundering herd sorununu azaltabilir
Zamanlayıcı durumunu tek bakışta görmek
systemctl list-timers, bir makinedeki zamanlayıcı durumunu özetleyen üst düzey bir komuttur
systemctl list-timers
NEXT LEFT LAST PASSED UNIT ACTIVATES
Mon 2026-04-20 15:15:00 MDT 1min 40s Mon 2026-04-20 15:00:05 MDT 13min ago zfs-snapshot-frequent.timer zfs-snapshot-frequent.service
Mon 2026-04-20 15:32:16 MDT 18min Mon 2026-04-20 14:22:15 MDT 51min ago fwupd-refresh.timer fwupd-refresh.service
Mon 2026-04-20 16:00:00 MDT 46min Mon 2026-04-20 15:00:05 MDT 13min ago logrotate.timer logrotate.service
Mon 2026-04-20 16:00:00 MDT 46min Mon 2026-04-20 15:00:05 MDT 13min ago zfs-snapshot-hourly.timer zfs-snapshot-hourly.service
Tue 2026-04-21 00:00:00 MDT 8h Mon 2026-04-20 09:43:22 MDT 5h 29min ago zfs-snapshot-daily.timer zfs-snapshot-daily.service
Tue 2026-04-21 07:31:28 MDT 16h Sun 2026-04-19 20:15:47 MDT 7h ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Mon 2026-04-27 00:00:00 MDT 6 days Mon 2026-04-20 09:43:22 MDT 5h 29min ago zfs-snapshot-weekly.timer zfs-snapshot-weekly.service
Mon 2026-04-27 01:09:27 MDT 6 days Mon 2026-04-20 09:43:22 MDT 5h 29min ago fstrim.timer fstrim.service
Mon 2026-04-27 04:28:38 MDT 6 days Mon 2026-04-20 09:43:22 MDT 5h 29min ago zpool-trim.timer zpool-trim.service
Fri 2026-05-01 00:00:00 MDT 1 week 3 days Wed 2026-04-01 10:07:51 MDT 1 week 1 day ago zfs-snapshot-monthly.timer zfs-snapshot-monthly.service
Fri 2026-05-01 03:17:17 MDT 1 week 3 days Wed 2026-04-01 10:07:51 MDT 1 week 1 day ago zfs-scrub.timer zfs-scrub.service
11 timers listed.
Pass --all to see loaded but inactive timers, too.
- Tek bir komutla, zamanlayıcı takvimine göre çalışan öğelerin genel görünümünü elde edebilirsiniz
list-timers, sık kullanılan systemd alt komutları ailesinin bir parçasıdır
list-units de kullanışlıdır
list-paths, systemctle daha yakın zamanda eklenen bir alt komuttur
Askı durumundayken uyandırıp çalıştırma
WakeSystem=, süresi dolan bir zamanlayıcının sistemi askı durumundan uyandırmasını sağlayabilir
WakeSystem=
Takes a boolean argument. If true, an elapsing timer will
cause the system to resume from suspend, should it be
suspended and if the system supports this.
...
- Bu özellik, birinin dizüstü bilgisayar kapağını açmasına gerek kalmadan önemli betiklerin çalışması gerektiğinde kullanışlıdır
- Arch ya da NixOS gibi, kullanımdan önce paket güncellemesi indirmeyi destekleyen dağıtımlarda, gece geç saatlerde güncelleme paketleri önceden indirilebilir ve sabah klavye başına geçtiğinizde güncelleme yapılabilir
- Kılavuzda,
.service tamamlandıktan sonra sistemin yeniden askıya alınmasını istiyorsanız bunun elle yeniden yapılması gerektiği belirtilir
Çalışma zamanlarını dağıtma ve thundering herd etkisini azaltma
- thundering herd sorunu, birçok sürecin aynı anda uyanmasıyla ortaya çıkan bir sistem problemidir
- Dünyadaki tüm Debian sistemleri
00:00:00 anında apt update çalıştıracak şekilde sabit kodlanmış olsaydı, gece yarısı herkes için kötü bir trafik zirvesi olurdu
FixedRandomDelay= ve RandomizedOffsetSec= çalışma zamanlarını dağıtmaya yardımcı olur
FixedRandomDelay=
Takes a boolean argument. When enabled, the randomized delay
specified by RandomizedDelaySec= is chosen deterministically,
and remains stable between all firings of the same timer,
even if the manager is restarted. ...
RandomizedOffsetSec=
Offsets the timer by a stable, randomly-selected, and evenly
distributed amount of time between 0 and the specified time
value. ...
- Bu ayarlar, yazılım güncellemelerini kontrol eden gerçek sistemlerde kullanılabilir
- Çalıştırmaları eşit dağılımla yaymak, thundering herd sorununu azaltmaya; davranışı tutarlı hale getirmeye ve dağıtık servisleri koordine eden arka plan süreçlerinin yeniden başlatılması gibi bozucu faaliyetlerden kaçınmaya yardımcı olur
- Zamanlama seçenekleri genel olarak çok yapılandırılabilir ve ince taneli denetim sunar
Kaçırılan çalıştırmaları hemen telafi etme
Persistent=, özellikle askıdaki dizüstü bilgisayar yüzünden kaçırılmaması gereken ama WakeSystem= kadar da gerekli olmayan zamanlanmış betikler için uygundur
Persistent=
Takes a boolean argument. If true, the time when the service
unit was last triggered is stored on disk. When the timer is
activated, the service unit is triggered immediately if it
would have been triggered at least once during the time when
the timer was inactive. ...
- Yapılandırma yönetimi check-in'i planlanmış bir sistem kesinti yaşadıysa,
.timer içine yalnızca Persistent= eklemek bile sistem çevrimiçi olur olmaz doğru duruma yakınsamasını sağlayabilir
Persistent= yoksa zamanlayıcının normal çalışma anını beklemeniz gerekebilir ve bu süre uzun olabilir
- Kaçırılan etkinleştirmeyi fark ettiğinde beklememesi gereken başka işler arasında sistem güncellemeleri ve toplu iş kontrolleri de vardır
Zamanlayıcı yazarken dikkat edilmesi gerekenler
systemctl --user ile yönetilen kullanıcı yöneticisi bağlamındaki zamanlayıcılar da geçerlidir, ancak [Install] içinde kullanılacak hedefe dikkat etmek gerekir
- Dağıtıma bağlı olarak kullanıcı zamanlayıcıları için uygun hedef
default.target olabilir
- Tıpkı
cronda olduğu gibi, sistem saatinin doğru tutulmasına dair genel uyarı burada da geçerlidir
- systemd kullanıcıları eşzamanlama durumunu
timedatectl timesync-status ile kontrol edebilir
- Birçok düzenleyici systemd ünite dosyası biçimini varsayılan olarak destekler; bu da ünite dosyaları büyüdüğünde yardımcı olur
- Emacs'te emacs systemd paketi kullanılabilir
1 yorum
Lobste.rs görüşleri
systemd mükemmel değil ama birçok tasarım kararının daha geleneksel eski yaklaşımlardan çıkarılan derslere dayandığı hissine kapılıyorum
Yakın zamanda Lennart Poettering’in bunun arka planını anlattığı CRE’nin 2015 tarihli bölümünü yeniden dinledim; hâlâ tavsiye etmeye değer
İçten içe systemd’den hiç hoşlanmayan taraftayım ama systemd.timers’ın bu üründeki “eh işte daha iyi” fikirlerden biri olduğunu düşünüyorum
Bu yüzden yazarın, geçerli şikâyetleri olan insanları küçümser gibi savunmaya geçmesi biraz şaşırtıcıydı
Yine de
atkomutuyla birlikte kullanmak güzel. Belirli bir zamanda bir kez çalıştırılacak komutlar içinat, diğer her şey içinse systemd zamanlayıcıları ve basit unit dosyaları kullanıyorumEn çok görmek istediğim iyileştirme, zamanlayıcıyı hangi kullanıcının çalıştırdığını görebilmek. 2026’da shell box işleten sayılı insanlardan biri olabilirim ama her saniye diske vuran bir zamanlayıcıyı hangi kullanıcının oluşturduğunu bilmek faydalı olurdu
loginctl enable-lingerile etkin bir kullanıcı oturumu olmadan da çalışabildiklerini sanıyorum. Elbette bunun yetmeyeceği kullanım örnekleri de vardır, somut durumu bilmiyorumÖzellikle kullanıcı yönetimi tarafında systemd zamanlayıcılarının başlangıç yükü daha düşük olsa iyi olurdu
Gerekli yapılandırma miktarına bakınca
crontab -e’yi geçmek gerçekten zorCron betiği loglarını düzenli biçimde toplamanın bir yolunu uzun süre düşündükten sonra, aslında sadece systemd zamanlayıcıları kullanmam gerektiğini fark ettim
Loglama sorunu çözülmüş oldu. Artık cron’a geri dönmek için bir nedenim yok; keşke bunu daha önce bilseydim
loggerile pipe etmek ya da log dosyasına>>ile eklemek veya varsayılanı bırakıp e-posta almak yeterli değil mi?İstediğiniz kadar eski kafalı deyin ama sunucudan bana ulaşan e-postayı hâlâ yapılandırıyorum
Otomatikleştirince her yeni hostta bedavaya geliyor ve günlük kullanımda da oldukça pratik
Örneğin bir multiplexer açıp
long_running_process | mail root@localhost -s "done $?"çalıştırıyor ve sonra unutuyorumGüzel bir yazı; benim de benzer bir yazının taslağı vardı ve yakın zamanda tekrar başvurmam gerekti
Benim gibi systemd tavşan deliğine girerseniz, ilgili proje klasöründeki unit dosyalarını ve zamanlayıcıları
/etc/systemd/system/içine sembolik bağlantı ile koymanızı öneririmsystemd ile ilgili bir şikâyetim, dağıtımın kurduğu unit’lerle benim yazdığım unit’leri ayırt etmemesi; sembolik bağlantılarla bu ayrımı kendiniz koruyabilirsiniz
Sistem/paket/dağıtım unit’leri
/usr/lib/systemd/systemaltında olur, yerel override’lar veya yerel unit’ler ise/etc/systemd/systemaltında yer alır