Skip to content
VDS · التطبيقات والبوتات

المهام المجدولة: cron ومؤقتات systemd

كيفية تشغيل المهام المجدولة، ولماذا تعمل المهمة يدويًا لكنها تبقى صامتة في cron، ومتى تنتقل إلى مؤقتات systemd.

آخر تحديث 23 أغسطس 2026

النسخ الاحتياطية، تجديد الشهادات، تنظيف الملفات المؤقتة، التقارير الليلية — كل هذه مهام مجدولة. على Linux تحلها بطريقتين: cron الكلاسيكي ومؤقتات systemd.

Cron: البداية السريعة

تحرر جدول المستخدم هكذا:

crontab -e
crontab -l

تنسيق السطر هو خمسة حقول ثم أمر:

# min  hour  day  month  day-of-week  command
  0    4    *     *      *            /usr/local/bin/backup.sh
  */15 *    *     *      *            /usr/local/bin/check.sh
  30   3    *     *      0            /usr/bin/systemctl restart myapp

اختصارات مفيدة: @daily، @hourly، @reboot. للتحقق من أن المهام نُفذت أصلًا:

grep CRON /var/log/syslog | tail -30
journalctl -u cron --since "1 hour ago"

لماذا يعمل السكربت يدويًا ولا يعمل في cron

هذه هي المشكلة الأكثر شيوعًا، والسبب دائمًا تقريبًا واحد من ثلاثة.

بيئة مختلفة. يمتلك cron قيمة PATH ضئيلة ولا يملك أيًا من متغيراتك من .bashrc. استخدم المسارات الكاملة للبرامج واضبط المتغيرات صراحةً في أعلى السكربت أو في crontab:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

دليل مختلف. تبدأ المهمة من دليل المستخدم الرئيسي، لذا تشير المسارات النسبية إلى مكان آخر. استخدم دائمًا مسارات مطلقة.

المخرجات تذهب إلى لا مكان. حدث خطأ، لكن لم يره أحد. اكتب سجلًا:

0 4 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

ملاحظتان صغيرتان أخريان: يجب تهريب محرف % في سطر cron على هيئة \%، ويجب أن ينتهي ملف crontab بسطر جديد — وإلا تُتجاهل المهمة الأخيرة.

تحتاج إلى التحقق من الخارج من أن المهمة نُفذت. يبدو cron الصامت تمامًا كـ cron الناجح. أعدّ فحص دفع في Uptime Kuma: يرسل السكربت طلبًا إلى عنوان في النهاية، وإذا لم يرسل طلبًا ليوم كامل، تصلك تنبيه.

مؤقتات systemd

عندما تكون المهمة أعقد من أمر واحد، يكون المؤقت أكثر ملاءمة: فهو يمتلك سجلًا واعتماديات وحدود موارد وحماية من تشغيل نسختين في آن واحد.

# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
# /etc/systemd/system/backup.timer
[Unit]
Description=Run nightly backup

[Timer]
OnCalendar=*-*-* 04:00:00
Persistent=true
RandomizedDelaySec=15m

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers
journalctl -u backup.service -n 50

يعوّض Persistent=true التشغيل الفائت إذا كانت الآلة متوقفة — وهو ما لا يستطيعه cron. يوزّع RandomizedDelaySec الحمل حتى لا تبدأ عشرات المهام في الثانية نفسها.

ما يجب أن تضعه في الحسبان

  • وقت الآلة هو UTC افتراضيًا. تحقق من timedatectl قبل أن تضبط «الرابعة صباحًا».
  • المهام الثقيلة (الأرشيفات، التحقق من النسخ الاحتياطية) مرتبطة بسرعة القرص. راجع سرعة القرص وجدولها ليلًا.
  • المهمة الطويلة التي تعمل كل خمس دقائق ستتداخل مع نفسها. في systemd يساعد Type=oneshot؛ وفي cron استخدم قفلًا عبر flock:
*/5 * * * * /usr/bin/flock -n /tmp/job.lock /usr/local/bin/job.sh