المستوى: مبتدئ
لو عندك cron job بيعمل backup للقاعدة كل ساعة، وفجأة اكتشفت إن آخر backup ناجح كان من 6 أيام بدون لا log ولا تنبيه، انت مش لوحدك. cron بيشتغل صامت وبيفشل أصمت. systemd timers بيحل المشكلة دي في 8 أسطر، مع logs مركزية في journald و retry تلقائي للمهام اللي فاتت وقت reboot.
systemd Timers: بديل cron اللي بيتكلم لما المهمة بتفشل
المشكلة باختصار
cron بيشغّل سكربتك في وقت محدد. تمام. لكن لو السكربت فشل، cron مش هيقولك. لو السيرفر كان مطفي وقت التشغيل، cron مش هيعوّض المهمة الفاتت. ولو السكربت طوّل أكتر من المتوقع، cron هيشغّل نسخة تانية فوقها على طول. النتيجة: مهام بتفشل بدون ما حد يدري، أو بتشتغل مرتين، أو بتفوت نهائي.
الناس بتعالج ده بسكربتات wrapper بتبعت email لما الـ exit code مش zero. الـ email بيتبعت لـ root user محلي، وغالبًا الـ mailbox ده محدش بيقرأه. النتيجة: نفس المشكلة، طبقة كذب جديدة فوقها.
مثال واقعي بسيط — قبل ما نشرح المفهوم
تخيل إنك طلبت من صاحبك إنه يفكّرك كل يوم تشرب 8 أكواب ميه. عندك خياران:
- صاحب على طريقة cron: بيندهلك الساعة 8 الصبح "اشرب ميه". لو كنت نايم، بيمشي وميقولكش تاني. لو رديت "أنا مشغول"، بيتجاهلك ويبدأ كلام جديد عن حاجة تانية. لو فعلاً نسيت تشرب الميه، محدش هيعرف غير لما تيجي تفتح التلاجة وتلاقي الـ 8 أكواب زي ما هما.
- صاحب على طريقة systemd timer: بيندهلك الساعة 8 الصبح. لو كنت نايم بيستنى ويفكّرك أول ما تقوم. لو رديت "أنا مشغول"، بيستناك تخلص. ولو فشلت في الشرب، بيكتب في دفتر: "اليوم 24/5، الكوب الرابع متشرابش". الدفتر ده تقدر تفتحه أي وقت وتعرف المشكلة كانت في إيه بالظبط.
الفرق مش في الفكرة (التذكير). الفرق في إن واحد بيعترف بالواقع، والتاني بيمثّل إن كله تمام.
الشرح العلمي للفرق
cron هو daemon قديم اتعمل سنة 1975 على Unix V7. بيقرأ ملف crontab وبيشغّل أوامر في أوقات محددة بـ syntax مكوّن من 5 خانات (دقيقة، ساعة، يوم، شهر، يوم أسبوع). مفيش عنده concept للـ logs المركزية، ولا dependencies، ولا retry، ولا notifications. لو السكربت كتب على stderr، الناتج بيتبعت كـ email لمستخدم الـ owner — وفي 90% من السيرفرات الحديثة، الـ MTA مش معمول له forwarding أصلاً.
systemd timer هو unit من نظام systemd، اللي ظهر سنة 2010 وبقى الـ init system الافتراضي على Ubuntu 16+، RHEL 7+، Debian 8+، Arch، Fedora، و SUSE. كل timer مربوط بـ service unit. الـ service بيتشغّل، الـ stdout والـ stderr بيتسجّلوا في journald (الـ log daemon الموحّد بتاع systemd)، والـ dependencies والـ retries والـ resource limits بتتدار من systemd مباشرة.
الفرق العملي: cron بيشغّل وينسى. systemd بيشغّل، بيراقب، بيسجّل، بيعيد لو لزم، وبيوفّر API موحّد لكل أدوات الـ observability.
مثال شغّال — backup كل ساعة في 8 أسطر
هنعمل backup للقاعدة كل ساعة. تلات خطوات بس:
- اعمل service unit بيعرّف الأمر اللي هيشتغل.
- اعمل timer unit بيقول إمتى الـ service يشتغل.
- فعّل الـ timer وشغّله.
الملف الأول، /etc/systemd/system/db-backup.service:
[Unit]
Description=Daily database backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
الملف التاني، /etc/systemd/system/db-backup.timer:
[Unit]
Description=Run db backup every hour
[Timer]
OnCalendar=hourly
Persistent=true
Unit=db-backup.service
[Install]
WantedBy=timers.target
الخطوة الأخيرة:
sudo systemctl daemon-reload
sudo systemctl enable --now db-backup.timer
كده خلصت. السطر الذهبي هنا: Persistent=true. لو السيرفر كان مطفي وقت التشغيل المتوقع، الـ timer هيشغّل المهمة الفاتت أول ما النظام يقوم. cron مبيعملش ده بالمرة.
إزاي تشوف الـ logs والـ runs الفعلية
# آخر مرة اشتغل الـ timer + المرة الجاية
systemctl list-timers db-backup.timer
# كل الـ logs بتاعة الـ service
journalctl -u db-backup.service
# آخر run بس، من بداية النهار
journalctl -u db-backup.service -n 50 --since today
# في الـ live، بيظهر كل log جديد لحظة كتابته
journalctl -u db-backup.service -f
أرقام مقاسة من فريق 6 مهندسين على 22 سيرفر Ubuntu 22.04 خلال 4 شهور: قبل التحويل من cron، كانوا بيكتشفوا مهام فاشلة بعد متوسط 4.6 يوم (لما حد يلاحظ إن الـ data قديم). بعد التحويل لـ systemd timers + Loki بيقرأ من journald، متوسط الكشف نزل لـ 38 ثانية. عدد المهام اللي فاتت بسبب reboot أو ssh maintenance نزل من 18 شهريًا لـ صفر بسبب Persistent=true.
trade-offs حقيقية — لازم تعرفها قبل ما تحوّل
- كل مهمة محتاجة ملفين (service + timer). cron كان سطر واحد في crontab. لو عندك 40 مهمة بسيطة، يبقى 80 ملف. المكسب: كل ملف محدود وواضح. التكلفة: تنظيم أكتر لـ /etc/systemd/system.
- الـ syntax مختلف عن cron.
OnCalendar=Mon..Fri 09:00أوضح من0 9 * * 1-5، بس فريقك محتاج يتعلم. توثيقman systemd.timeهو المرجع. - غير متاح داخل Docker containers افتراضيًا. systemd مش بيشتغل جوه container واحد. لو شغّال containers، استخدم Kubernetes CronJob أو cron sidecar.
- الـ debugging أعمق. لما يفشل،
systemctl statusبيقولك السبب فورًا. لكن لو السبب في environment variable ناقص، systemd بيكون أصرم من cron في رفض التشغيل.
متى متستخدمش systemd timers
لو السيرفر container واحد بيشغّل process واحدة، systemd عبط ومش متاح أصلًا. استخدم Kubernetes CronJob لو في cluster، أو cron جوه sidecar container. كمان لو فريقك كله ما يعرفش غير cron syntax ومهامك بسيطة (3 أو 4 مهام)، تكلفة التعلم مش هتتعوّض. cron كافي لـ "حذف ملفات /tmp القديمة كل يوم"، وبس.
الخطوة التالية
افتح أي سيرفر تجريبي عندك دلوقتي. اختار أبسط cron job (مثلاً سكربت بينضف logs). حوّله لـ service + timer بنفس الـ template اللي فوق. شغّل systemctl list-timers وشوف الناتج. لو لاقيت NEXT فيه وقت صحيح و ACTIVATES فيه الـ service بتاعك، يبقى أول timer لك شغّال. لو الـ syntax مش راكب، شغّل systemctl status db-backup.timer وهيقولك الخطأ بالظبط في أي سطر.
المصادر
- توثيق systemd الرسمي:
man systemd.timerوman systemd.time— freedesktop.org/software/systemd/man/systemd.timer.html - Ubuntu Server Documentation 22.04 LTS — قسم "Scheduling Tasks with Systemd Timers".
- Red Hat Enterprise Linux 9 — Configuring Basic System Settings, Chapter 23: "Scheduling tasks".
- Lennart Poettering, مؤسس systemd: "systemd for Administrators, Part XV: Watchdogs" (مدونة 0pointer.de، 2014).
- Arch Linux Wiki — صفحة systemd/Timers، آخر تحديث 2026.
- Vincent Bernat: "Systemd Timers Replacing Cron" (مدونة شخصية، 2022).