مدیریت یک سرور معمولاً شامل تعداد زیادی کار تکراری است؛ از گرفتن نسخه پشتیبان و پاکسازی فایلهای موقت گرفته تا اجرای اسکریپتهای مانیتورینگ، تولید گزارش یا همگامسازی اطلاعات.
اجرای دستی این کارها هم زمانبر است و هم احتمال فراموشی یا خطای انسانی را افزایش میدهد. در سیستمهای لینوکسی یکی از سادهترین ابزارها برای خودکارسازی این وظایف Cron است.
Cron به شما اجازه میدهد یک دستور یا اسکریپت را طبق یک برنامه زمانی مشخص اجرا کنید؛ مثلاً:
- هر پنج دقیقه
- هر شب ساعت ۲
- هر دوشنبه
- اولین روز هر ماه
- یا در زمانهای مشخص دیگر
اما استفاده قابلاعتماد از Cron فقط به نوشتن پنج ستاره محدود نمیشود. Environment، مسیر فایلها، Permission، Timezone، مدیریت خطا، جلوگیری از اجرای همزمان Jobها و مانیتورینگ سرور نیز اهمیت دارند.
در این راهنما از مفاهیم پایه شروع میکنیم و سپس به Cron Expression، Crontab، اجرای Script، Logging، امنیت، Troubleshooting و جایگزینهایی مانند systemd timer و Kubernetes CronJob میرسیم.
Cron چیست؟
Cron یک زمانبند مبتنی بر زمان در سیستمهای Unix-like است که وظایف تعریفشده را طبق زمانبندی مشخص اجرا میکند.
Cron معمولاً بهعنوان یک سرویس پسزمینه یا Daemon فعالیت میکند و برنامههای زمانی ثبتشده را بررسی میکند تا در زمان مناسب Command مربوط به هر Job را اجرا کند.
خود Cron منطق کار شما را انجام نمیدهد. وظیفه آن مشخصکردن زمان اجرای یک Command یا Script است.
برای مثال میتوانید از Cron برای اجرای موارد زیر استفاده کنید:
- تهیه نسخه پشتیبان
- اجرای Script مانیتورینگ
- پاکسازی Cache یا فایلهای موقت
- تولید گزارش
- همگامسازی داده
- اجرای Queue یا Taskهای نگهداری
- فراخوانی یک Command در پروژه
- اجرای Scriptهای مدیریتی
تفاوت Cron، Cron Job و Crontab چیست؟
این سه اصطلاح به یکدیگر مرتبط هستند اما معنی یکسانی ندارند.
Cron
Cron همان سرویس یا Scheduler است که زمان اجرای وظایف را مدیریت میکند.
Cron Job
Cron Job یک وظیفه زمانبندیشده است.
برای مثال:
هر روز ساعت ۲ بامداد Script پشتیبانگیری اجرا شود.
این یک Cron Job محسوب میشود.
Crontab
Crontab هم نام جدولی است که برنامههای Cron در آن تعریف میشوند و هم نام Commandای است که برای مدیریت Cron Job های کاربر استفاده میشود.
برای مثال:
crontab -e
Crontab کاربر فعلی را برای ویرایش باز میکند.
Cron چگونه کار میکند؟
بهشکل ساده، روند کار Cron به این صورت است:
- Cron Service در سیستم فعال است.
- برنامههای موجود در Crontab را بررسی میکند.
- زمان فعلی با Cron Expression هر Job مقایسه میشود.
- اگر Schedule مطابق زمان فعلی باشد، Command مربوط به Job اجرا میشود.
- خروجی و خطا براساس تنظیمات Job، Cron و سیستم مدیریت میشود.
در پیادهسازیهای رایج Cron، بررسی Schedule با دقت دقیقه انجام میشود. بنابراین Cron کلاسیک برای زمانبندی در سطح ثانیه طراحی نشده است.
سینتکس Cron چگونه است؟
در Crontab معمولی کاربر، هر Job شامل پنج فیلد زمانی و سپس Command است:
* * * * * command
│ │ │ │ │
│ │ │ │ └── روز هفته
│ │ │ └──── ماه
│ │ └────── روز ماه
│ └──────── ساعت
└────────── دقیقه
ساختار آن:
| فیلد | مقادیر رایج |
|---|---|
| دقیقه | 0 تا 59 |
| ساعت | 0 تا 23 |
| روز ماه | 1 تا 31 |
| ماه | 1 تا 12 |
| روز هفته | معمولاً 0 تا 7؛ 0 و 7 یکشنبه |
| Command | دستور یا Script موردنظر |
برای مثال:
0 2 * * * /usr/local/bin/backup.sh
یعنی Script هر روز ساعت ۲ بامداد اجرا شود.
کاراکترهای مهم Cron Expression
ستاره *
یعنی تمام مقادیر آن فیلد.
* * * * *
یعنی هر دقیقه.
کاما ,
برای مشخصکردن چند مقدار:
0,30 * * * *
یعنی در دقیقه صفر و ۳۰ هر ساعت.
خط تیره -
برای یک بازه:
0 9 * * 1-5
یعنی ساعت ۹ صبح روزهای دوشنبه تا جمعه.
اسلش /
برای Step:
*/10 * * * *
یعنی هر ۱۰ دقیقه.
نمونه Cron Jobهای پرکاربرد
| Cron Expression | زمان اجرا |
|---|---|
* * * * * |
هر دقیقه |
*/5 * * * * |
هر ۵ دقیقه |
0 * * * * |
ابتدای هر ساعت |
0 0 * * * |
هر روز نیمهشب |
0 2 * * * |
هر روز ساعت ۲ بامداد |
0 3 * * 1 |
دوشنبهها ساعت ۳ |
30 23 * * 5 |
جمعه ساعت ۲۳:۳۰ |
0 */6 * * * |
هر ۶ ساعت |
15 2 1 * * |
روز اول هر ماه ساعت ۲:۱۵ |
یک نکته مهم درباره Day-of-Month و Day-of-Week
یکی از نکات کمتر شناختهشده Cron مربوط به این دو فیلد است:
- Day of Month
- Day of Week
در پیادهسازیهای رایج Vixie/Cronie اگر هر دو فیلد محدود شده باشند، اجرای Job ممکن است زمانی انجام شود که یکی از آن دو Match شود، نه الزاماً هر دو.
به همین دلیل برای Scheduleهای پیچیده بهتر است Expression را قبل از Production دقیق بررسی و آزمایش کنید.
Macroهای Cron
برخی پیادهسازیهای Cron علاوه بر Syntax پنجفیلدی از Macroهای سادهتر نیز پشتیبانی میکنند.
نمونههای رایج:
@hourly
@daily
@weekly
@monthly
@yearly
@reboot
برای مثال:
@daily /usr/local/bin/report.sh
یعنی اجرای Script بهصورت روزانه.
پشتیبانی دقیق از Macroها میتواند به Cron Implementation سیستم بستگی داشته باشد.
کار با Crontab
ساخت یا ویرایش Cron Job
برای ویرایش Crontab کاربر فعلی:
crontab -e
هر خط یک Cron Job مستقل است.
مشاهده Cron Jobها
crontab -l
حذف Crontab
crontab -r
این دستور میتواند تمام Crontab کاربر را حذف کند؛ بنابراین قبل از استفاده از آن بهتر است نسخهای از تنظیمات فعلی نگه دارید:
crontab -l > ~/crontab-backup.txt
تفاوت User Crontab و System Crontab
Crontab کاربر و Crontabهای سطح سیستم دقیقاً Syntax یکسانی ندارند.
در Crontab کاربر:
0 2 * * * /usr/local/bin/backup.sh
کاربر اجراکننده از قبل مشخص است.
اما در فایلهایی مانند:
/etc/crontab
یا معمولاً فایلهای:
/etc/cron.d/
یک فیلد اضافه برای نام کاربری وجود دارد:
0 2 * * * backupuser /usr/local/bin/backup.sh
همچنین محل ذخیره Crontabهای کاربران میتواند بین توزیعها و Cron Implementationهای مختلف متفاوت باشد؛ بنابراین بهتر است این فایلها را مستقیماً ویرایش نکنید و برای Crontab کاربر از Command رسمی crontab استفاده کنید.
اجرای Script با Cron
یکی از رایجترین استفادههای Cron اجرای Script است.
فرض کنیم Script زیر را داریم:
#!/bin/bash
echo "Job executed at $(date)" >> /var/log/my-job.log
اگر Script مستقیماً اجرا میشود:
/usr/local/bin/my-job.sh
باید Shebang و Permission مناسب داشته باشد.
مثلاً:
chmod +x /usr/local/bin/my-job.sh
اما میتوانید Interpreter را نیز صریحاً مشخص کنید:
0 2 * * * /bin/bash /usr/local/bin/my-job.sh
در این حالت، executable bit خود Script همیشه همان نقش حالت اجرای مستقیم را ندارد.
چرا Script در Terminal اجرا میشود ولی در Cron نه؟
یکی از رایجترین مشکلات Cron همین است.
Cron معمولاً Environment محدودتری از Shell تعاملی شما دارد. در نتیجه مواردی که در Terminal کار میکنند ممکن است در Cron پیدا نشوند.
از مسیر کامل Commandها استفاده کنید
بهجای:
python script.py
ترجیحاً مسیر دقیق را مشخص کنید:
/usr/bin/python3 /home/user/scripts/script.py
PATH را مشخص کنید
میتوانید در Crontab تعیین کنید:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Working Directory را فراموش نکنید
اگر Script انتظار دارد در مسیر خاصی اجرا شود:
0 2 * * * cd /var/www/example && /usr/bin/php artisan schedule:run
Environment Variableها را مدیریت کنید
اگر Script به متغیرهایی مانند:
DATABASE_URL
NODE_ENV
API_KEY
نیاز دارد، نباید فرض کنید Cron همان Environment Session SSH شما را در اختیار دارد.
برای Secretها نیز بهتر است از فایل تنظیمات با Permission مناسب یا Secret Management مناسب استفاده شود و اطلاعات حساس مستقیماً داخل Crontab نوشته نشوند.
یک نکته کمتر شناختهشده درباره علامت %
در برخی Cron Implementationها کاراکتر % داخل Command معنی خاصی دارد و میتواند به Newline تبدیل شود.
برای مثال اگر Command پیچیدهای شامل:
date +%F
باشد، بهتر است آن را داخل یک Script قرار دهید یا % را متناسب با Implementation بهدرستی Escape کنید.
قرار دادن منطق پیچیده داخل Script معمولاً خوانایی و عیبیابی Cron Job را هم بهتر میکند.
مدیریت خروجی و خطا
فقط اینکه Cron یک Command را اجرا کرده، به معنی موفقیت عملیات داخل Script نیست.
برای Jobهای مهم باید خروجی و خطا قابل بررسی باشند.
ذخیره stdout و stderr
0 2 * * * /usr/local/bin/my-job.sh >> /var/log/my-job.log 2>&1
>> خروجی معمولی را به انتهای فایل اضافه میکند و:
2>&1
خطای استاندارد را نیز به همان مقصد هدایت میکند.
مراقب بزرگشدن فایل Log باشید
اگر Job مرتب اجرا شود، فایل Log میتواند بهمرور بسیار بزرگ شود.
برای سرویس Production باید Log Rotation یا سیستم Logging مناسب داشته باشید.
ارسال خروجی به /dev/null
برای خروجی واقعاً غیرضروری میتوان از:
*/5 * * * * /usr/local/bin/task.sh > /dev/null 2>&1
استفاده کرد.
اما این روش برای Jobهای حیاتی مانند Backup، Billing، Sync یا پردازشهای مهم توصیه نمیشود؛ زیرا عیبیابی Failure را دشوار میکند.
Cron Log را کجا ببینیم؟
محل Log به توزیع، Cron Implementation و Logging Stack سیستم بستگی دارد.
در بعضی سیستمهای Debian/Ubuntu ممکن است رویدادها در:
/var/log/syslog
دیده شوند.
در برخی سیستمهای دیگر:
/var/log/cron
استفاده میشود.
در سیستمهای مبتنی بر systemd نیز میتوانید بسته به نام سرویس از Journal استفاده کنید:
journalctl -u cron
یا:
journalctl -u crond
نکته مهم این است که Log سرویس Cron ممکن است فقط نشان دهد Command شروع شده است. برای فهمیدن موفقیت واقعی Script باید Application Log و Exit Status نیز بررسی شوند.
در پچیم نیز برای بررسی وضعیت سرور میتوانید از بخش مانیتورینگ و مدیریت لاگهای سرور استفاده کنید.
ایمیل خروجی Cron
برخی Cron Implementationها میتوانند خروجی Job را از طریق Mail برای کاربر ارسال کنند.
برای مشخصکردن گیرنده:
MAILTO="admin@example.com"
و برای غیرفعالکردن:
MAILTO=""
اما این قابلیت تنها زمانی کاربردی است که Mail Transport مناسب روی سرور تنظیم شده باشد. در غیر این صورت ممکن است خروجی ایمیلی ارسال نشود.
جلوگیری از اجرای همزمان Cron Job
فرض کنید یک Job هر پنج دقیقه اجرا میشود اما بعضی اوقات اجرای آن هشت دقیقه طول میکشد.
در این شرایط اجرای دوم میتواند قبل از پایان اجرای اول شروع شود.
نتیجه ممکن است شامل این موارد باشد:
- پردازش دوباره داده
- مصرف بیش از حد CPU و RAM
- ایجاد Conflict در Database
- ساخت Backupهای همزمان
- Race Condition
یکی از روشهای ساده در لینوکس استفاده از flock است:
*/5 * * * * flock -n /var/lock/my-job.lock /usr/local/bin/my-job.sh
گزینه -n باعث میشود اگر Lock قبلاً گرفته شده است، اجرای جدید منتظر نماند و اجرا نشود.
برای Jobهای مهم بهتر است علاوه بر Lock، خود عملیات نیز تا حد امکان Idempotent طراحی شود؛ یعنی اجرای دوباره آن باعث آسیب یا داده تکراری نشود.
مدیریت مصرف CPU و Disk
Jobهای سنگین مانند Backup یا پردازش فایل بهتر است در ساعات کمترافیک اجرا شوند.
برای کاهش Priority پردازش میتوان از nice استفاده کرد:
0 3 * * * nice -n 10 /usr/local/bin/heavy-job.sh
برای Workloadهایی که I/O زیادی دارند نیز در سیستمهای مناسب میتوان ionice را بررسی کرد.
نکات امنیتی Cron Job
Cron میتواند Command را با Permission کاربری که Job متعلق به اوست اجرا کند. بنابراین یک Cron Job دارای دسترسی بالا میتواند خطر امنیتی قابلتوجهی ایجاد کند.
چند اصل مهم:
از Root فقط در صورت نیاز استفاده کنید
اگر یک Job با کاربر محدود قابل اجراست، آن را با Root اجرا نکنید.
Script قابل ویرایش توسط کاربر غیرمجاز نباشد
اگر Root Cron یک Script را اجرا کند ولی کاربر دیگری بتواند Script را تغییر دهد، آن کاربر میتواند عملاً Command دلخواه خود را با دسترسی Root اجرا کند.
از مسیر کامل Commandها استفاده کنید
این کار علاوه بر کاهش خطا، احتمال اجرای Binary اشتباه از PATH را کم میکند.
Secret را داخل Crontab قرار ندهید
مثلاً بهتر است این کار انجام نشود:
PASSWORD=my-super-secret-password
بهخصوص اگر افراد دیگری امکان مشاهده فایل یا Backup آن را داشته باشند.
ورودیهای خارجی را Validate کنید
اگر Script دادهای از API، فایل، User Input یا Database دریافت میکند، Cron باعث امنشدن آن Script نمیشود.
Cron و Timezone
Cron Schedule براساس زمان سیستم یا تنظیمات مربوط به Scheduler ارزیابی میشود.
قبل از Production بررسی کنید:
timedatectl
و مطمئن شوید Timezone همان چیزی است که انتظار دارید.
این مسئله مخصوصاً در سرورهای خارج از ایران مهم است، زیرا ممکن است Server روی UTC تنظیم شده باشد.
Cron و تغییر ساعت تابستانی
در مناطقی که Daylight Saving Time دارند، برخی زمانها در سال ممکن است حذف یا تکرار شوند.
در نتیجه Jobی که دقیقاً در یک ساعت حذفشده Schedule شده باشد ممکن است اجرا نشود و زمانی که ساعت تکرار میشود ممکن است Job متناظر دوبار Match شود.
برای Jobهای حساس مالی، Billing یا پردازشهای دقیق زمانی بهتر است این مسئله در طراحی لحاظ شود.
Cron Job اجرا نمیشود؛ چه چیزهایی را بررسی کنیم؟
اگر Cron Job اجرا نمیشود، این موارد را بهترتیب بررسی کنید:
- آیا Cron Service فعال است؟
- آیا Cron Expression درست است؟
- Timezone سرور چیست؟
- Command بهصورت دستی اجرا میشود؟
- آیا از Absolute Path استفاده شده است؟
- Working Directory درست است؟
- Environment Variableها موجود هستند؟
- Permission فایل و Directory مناسب است؟
- User اجراکننده دسترسی لازم دارد؟
- stdout و stderr کجا میروند؟
- Cron Log چه چیزی نشان میدهد؟
- Script Exit Code چه بوده است؟
- آیا اجرای قبلی هنوز فعال است؟
- SELinux یا Policy امنیتی مانع اجرا شده است؟
- Disk Space یا منابع سیستم کافی هستند؟
اول Command را دقیقاً با همان Userای که Cron استفاده میکند بهصورت دستی اجرا کنید و سپس Logها را بررسی کنید.
systemd timer یا Cron؟
در بسیاری از توزیعهای مدرن لینوکس، systemd timer یک گزینه دیگر برای زمانبندی Taskهاست.
Systemd Timer میتواند برای سناریوهایی مناسب باشد که به مواردی مانند اینها نیاز دارند:
- وابستگی به Serviceهای دیگر
- Logging یکپارچه با Journal
- اجرای Job بعد از Boot
- کنترل دقیقتر Service
- Catch-up بعضی Jobهای از دسترفته با
Persistent= - مدیریت Resource و Dependency با systemd
Cron در مقابل برای بسیاری از Taskهای ساده و زمانمحور همچنان بسیار مناسب است.
بنابراین systemd timer را نمیتوان همیشه «بهتر» از Cron دانست؛ انتخاب به نیاز پروژه بستگی دارد.
ابزار at
اگر فقط میخواهید یک Command یکبار در آینده اجرا شود، at میتواند مناسبتر از Cron باشد.
برای مثال:
echo "/usr/local/bin/task.sh" | at 03:00
Cron بیشتر برای Taskهای تکرارشونده طراحی شده است.
Kubernetes CronJob
اگر برنامه شما داخل Kubernetes اجرا میشود، معمولاً بهتر است بهجای اجرای Cron Daemon داخل Container از Resource مخصوص Kubernetes یعنی CronJob استفاده کنید.
نمونه:
apiVersion: batch/v1
kind: CronJob
metadata:
name: example-job
spec:
schedule: "0 2 * * *"
timeZone: "Etc/UTC"
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
containers:
- name: job
image: example/image:latest
restartPolicy: OnFailure
Kubernetes CronJob قابلیتهایی مانند:
timeZoneconcurrencyPolicystartingDeadlineSeconds- نگهداری History اجراهای موفق و ناموفق
دارد.
از آنجا که در برخی شرایط ممکن است اجرای Schedule تکرار یا از دست برود، Jobهای مهم باید تا حد امکان Idempotent طراحی شوند.
Cloud Schedulerها
در معماری Cloud یا Serverless ممکن است اصلاً نیازی به Cron روی یک Linux Server نداشته باشید.
Amazon EventBridge Scheduler
در AWS، EventBridge Scheduler سرویس مدیریتشده فعلی برای زمانبندی Taskهاست و از Scheduleهای Cron، Rate و One-time پشتیبانی میکند.
Google Cloud Scheduler
Google Cloud Scheduler میتواند براساس Unix-cron Schedule، HTTP Endpoint، Pub/Sub یا App Engine را Trigger کند.
از آنجا که Delivery آن حداقل یکبار طراحی شده است، Endpoint باید اجرای احتمالی دوباره را بدون اثر مخرب مدیریت کند.
Azure Functions Timer Trigger
در Azure Functions میتوان با Timer Trigger Function را براساس Schedule اجرا کرد.
این گزینه برای Workloadهای Serverless که قرار نیست به یک Server مشخص وابسته باشند مناسب است.
زمانبندی وظایف با Scheduler پچیم
اگر سرور خود را با پچیم مدیریت میکنید، برای بسیاری از Taskهای زمانبندیشده نیازی نیست مستقیماً Crontab را ویرایش کنید.
در بخش Scheduler پچیم میتوانید برای سرور:
- Command موردنظر
- User اجراکننده
- Cron Schedule
را مشخص کنید و Task زمانبندیشده بسازید.
در صورت اجرا نشدن Job نیز میتوانید Log خروجی زمانبندی را از پنل بررسی کنید.
برای مثال در پروژه Laravel میتوان Command مربوط به:
php /path/to/project/artisan schedule:run
را هر دقیقه اجرا کرد تا Laravel Scheduler وظایف داخلی برنامه را مدیریت کند.
برای جزئیات بیشتر میتوانید مستندات «زمانبندی یا Scheduler» پچیم را مطالعه کنید.
Cron برای Backup مناسب است؟
Cron میتواند برای Trigger کردن Backup مناسب باشد، اما Cron بهتنهایی یک Backup Strategy کامل نیست.
در یک Backup مناسب باید علاوه بر Schedule به موارد زیر توجه شود:
- محل ذخیره نسخه پشتیبان
- نگهداری چند نسخه
- Retention Policy
- فضای ذخیرهسازی خارج از سرور اصلی
- Encryption
- مانیتورینگ Failure
- تست Restore
پچیم نیز قابلیت پشتیبانگیری زمانبندیشده از فایلها و دیتابیسها را ارائه میدهد که میتوانید تنظیمات آن را در مستندات Backup پچیم بررسی کنید.
Cron برای مانیتورینگ مناسب است؟
برای Checkهای ساده میتوان Script مانیتورینگ را با Cron اجرا کرد، اما برای مانیتورینگ جدی بهتر است از سیستم مانیتورینگ دائمی، Metric، Alert و Health Check استفاده شود.
Cron صرفاً Trigger اجرا را فراهم میکند و جای یک Monitoring Stack را نمیگیرد.
جمعبندی
Cron یکی از سادهترین و پرکاربردترین ابزارهای خودکارسازی Taskهای تکراری در Linux و سیستمهای Unix-like است.
برای ساخت یک Cron Job ساده کافی است Schedule و Command را در Crontab تعریف کنید، اما برای استفاده Production باید موضوعات دیگری مانند Environment، Permission، Logging، Lock، Timezone، DST، امنیت و Monitoring را نیز در نظر بگیرید.
برای Taskهای ساده روی یک سرور، Cron همچنان گزینه مناسبی است. در سیستمهای مبتنی بر systemd ممکن است Timer Unit کنترل بیشتری فراهم کند، در Kubernetes بهتر است از CronJob استفاده شود و در معماریهای Cloud یا Serverless نیز Schedulerهای مدیریتشده معمولاً انتخاب مناسبتری هستند.
اگر سرور خود را از طریق پچیم مدیریت میکنید، میتوانید Taskهای زمانبندیشده را از طریق Scheduler پنل پچیم تعریف و Log اجرای آنها را نیز بررسی کنید.