پرش به محتویات

۱۳. زمان‌بندی کارها

کار زمان‌بندی‌شده بی‌صدا شکست می‌خورد: کسی نگاهش نمی‌کند تا یک روز بفهمند سه ماه است بکاپ نگرفته. پس هر کار زمان‌بندی‌شده سه چیز لازم دارد: لاگ، قفل ضد هم‌پوشانی و سیگنال موفقیت.

راهنمای سریع

فرمان کاربرد ریسک
crontab -l / ls /etc/cron.d مشاهدهٔ cron بدون تغییر
systemctl list-timers --all فهرست timerها بدون تغییر
systemd-analyze calendar '...' آزمون عبارت زمانی بدون تغییر
crontab -e / at افزودن کار تغییر
crontab -r حذف همهٔ cron های کاربر، بدون تأیید مخرب

cron

crontab -l
crontab -e
sudo crontab -l
sudo crontab -l -u appuser
ls -lah /etc/cron.d/ /etc/cron.daily/
for u in $(cut -d: -f1 /etc/passwd); do sudo crontab -l -u "$u" 2>/dev/null | sed "s/^/$u: /"; done   # همهٔ کاربران

نمونه اجرای روزانه در ساعت 02:15 با قفل و لاگ:

# قالب: دقیقه ساعت روز-ماه ماه روز-هفته  فرمان
MAILTO=""
15 2 * * * flock -n /var/lock/backup.lock /usr/local/sbin/backup.sh >> /var/log/backup.log 2>&1
عبارت معنی
*/5 * * * * هر ۵ دقیقه
0 */6 * * * هر ۶ ساعت، دقیقهٔ ۰
30 1 * * 1-5 ۰۱:۳۰ دوشنبه تا جمعه (۱=دوشنبه … ۵=جمعه)
0 3 1 * * روز اول هر ماه ۰۳:۰۰
@reboot بعد از هر بوت
  • قالب: دقیقه، ساعت، روز ماه، ماه، روز هفته.
  • محیط cron محدود است (PATH حداقلی، بدون ترمینال)؛ مسیر کامل فرمان‌ها و متغیرهای محیطی لازم را صریح بنویسید.
  • خروجی و خطاها را ثبت کنید (>> log 2>&1) و اسکریپت را با همان کاربر و محیط تمیز آزمایش کنید: env -i /bin/sh -c '/usr/local/sbin/backup.sh'.
  • flock -n از اجرای هم‌زمان دو نمونه (وقتی اجرای قبلی هنوز تمام نشده) جلوگیری می‌کند.

دام‌های cron که همه یک بار می‌خورند

  • علامت % در خط cron یعنی «خط جدید»؛ باید \% نوشته شود (مثلاً date +\%F).
  • crontab -r بدون تأیید همهٔ cron ها را پاک می‌کند و کنار -e روی کیبورد است. از crontab -ri استفاده کنید یا قبلش crontab -l > backup.
  • اگر هم «روز ماه» و هم «روز هفته» را مقید کنید، شرایط OR می‌شوند، نه AND (0 0 13 * 5 = روز ۱۳ یا هر جمعه).
  • در /etc/cron.d/ هر خط ستون کاربر دارد (15 2 * * * root /path) و فایل باید مالک root و بدون دسترسی نوشتن گروه باشد.
  • فایل‌های داخل /etc/cron.daily و cron.d با نام دارای نقطه (backup.sh) در برخی توزیع‌ها نادیده گرفته می‌شوند (run-parts)؛ بدون پسوند و با اجرایی بودن بسازید.
  • cron با منطقهٔ زمانی سیستم و بدون جبران DST کار می‌کند؛ کار ساعت ۰۲:۳۰ در روز تغییر ساعت ممکن است دوبار یا هیچ‌بار اجرا شود. ترجیحاً سیستم روی UTC.

عیب‌یابی cron:

journalctl -u cron --since today        # RHEL: -u crond
grep CRON /var/log/syslog | tail        # Debian بدون journal
# دیدن محیط واقعی cron (موقت!): * * * * * env > /tmp/cronenv   — بعد از دیدن حذف کنید

systemd timer

برای سرویس‌های جدید، timer نسبت به cron امکاناتی مانند وابستگی سرویس، ثبت در journal، محدودیت منابع، اجرای عقب‌افتاده و تأخیر تصادفی را ساده‌تر می‌کند.

# /etc/systemd/system/backup.service   (نمونه)
[Unit]
Description=Nightly backup

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/backup.sh
User=root
Nice=10
# /etc/systemd/system/backup.timer     (نمونه)
[Unit]
Description=Nightly backup timer

[Timer]
OnCalendar=*-*-* 02:15:00
Persistent=true            # اگر سرور خاموش بود، بعد از بوت جبران کن
RandomizedDelaySec=300     # پخش بار روی چند سرور
Unit=backup.service

[Install]
WantedBy=timers.target
systemd-analyze calendar '*-*-* 02:15:00'      # نمایش زمان بعدی اجرا
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers --all | grep backup
sudo systemctl start backup.service            # اجرای دستی برای تست
journalctl -u backup.service --since today
systemctl status backup.service --no-pager     # exit code آخرین اجرا
systemctl list-timers --all
systemctl status logrotate.timer
systemctl cat logrotate.timer

at

at 23:00
at now + 30 minutes
atq
at -c JOB_ID          # محتوای کار
atrm JOB_ID

پس از اجرای at 23:00 فرمان‌ها را وارد و با Ctrl+D ثبت کنید. دسترسی به at ممکن است با سیاست سیستم (/etc/at.allow/at.deny) محدود شده باشد. at برای «برگرداننده»های موقت (rollback زمان‌دار) بسیار مفید است (فایروال).

بررسی زمان

timedatectl
date
chronyc tracking        # یا: timedatectl timesync-status

تنظیم timezone را با نیاز برنامه‌ها هماهنگ کنید. در سامانه‌های توزیع‌شده، UTC برای لاگ‌ها معمولاً ساده‌تر است؛ timezone نمایشی را مستند کنید. ساعت اشتباه = cron/گواهی/Kerberos/لاگ همه خراب.

خطاهای رایج

نشانه علت احتمالی روش بررسی
دستی کار می‌کند، در cron نه PATH/محیط/مسیر نسبی مسیر کامل؛ env -i ؛ لاگ با 2>&1
cron اجرا شد ولی خروجی نیست ایمیل محلی (MAILTO) >> log 2>&1 ؛ MAILTO=""
کار دوبار هم‌زمان اجرا می‌شود اجرای قبلی تمام نشده flock -n
فایل در cron.daily اجرا نمی‌شود نام با نقطه/غیر اجرایی run-parts --test /etc/cron.daily
date +%F در cron خراب % escape نشده \%
timer هرگز اجرا نمی‌شود enable نشده/عبارت اشتباه list-timers ، systemd-analyze calendar
timer اجرا شد ولی کار شکست خورد خطا در service systemctl status X.service ، journalctl -u X.service

نکات امنیتی و عملیاتی

  • cron/timer فایل‌های اسکریپت را باید فقط root بتواند تغییر دهد؛ اسکریپتی که root اجرا می‌کند ولی دیگران می‌نویسند = ارتقای دسترسی.
  • هر کار حیاتی «نبود موفقیت» را هشدار بدهد (heartbeat)؛ نه فقط خطا.
  • cron ها را در مخزن Git نگه دارید و دوره‌ای با سرور مقایسه کنید.

خلاصهٔ اجرایی

  1. مسیر کامل، flock، لاگ، \%.
  2. crontab -r را فراموش کنید؛ -ri.
  3. کار جدید → systemd timer با Persistent=true.
  4. آزمون با env -i و systemd-analyze calendar.