مرجع Crontab الشامل: 50+ تعبير cron وصيغته ودليل المُجدوِلات الحديثة
تعبير cron هو خمسة حقول (الدقيقة، الساعة، يوم الشهر، الشهر، يوم الأسبوع) متبوعة بأمر تنفيذي. تحرِّك هذه القواعد جدولة المهام في Unix منذ عام 1979، وتحرِّك اليوم أيضًا Kubernetes CronJobs وGitHub Actions وAWS EventBridge ومُحفِّزات Vercel cron، ويُستخدم القالب نفسه عبر هذه المنصات.
إذا كنت تحتاج تعبيرًا الآن لمهمة Linux أو Kubernetes CronJob أو مُحفِّز GitHub Actions، أو لتصحيح مهمة يُفترض أن تُنفَّذ كل خمس دقائق لكنها تنطلق كل ساعة، انظر جدول المرجع السريع للتعابير الجاهزة للنسخ، أو قسم شرح الصيغة لقواعد الحقول. ويمكنك التحقق من التعابير مباشرةً في مولد crontab — منشئ ومحلل تعبير cron — بديل crontab guru أولويةً للخصوصية يعمل في متصفحك —.
جدول المرجع السريع لتعابير cron
ثلاثون تعبيرًا تُغطِّي قرابة 90% من احتياجات الجدولة الفعلية. كلٌّ منها تعبير cron ذو خمسة حقول مطابق لـ POSIX، ويمكن لصقه في crontab -e، أو في حقل schedule: في Kubernetes، أو في cron: في GitHub Actions.
| الجدول الزمني | تعبير cron | بالعربية |
|---|---|---|
| كل دقيقة | * * * * * | كل دقيقة، طوال اليوم، كل يوم |
| كل 5 دقائق | */5 * * * * | الدقيقة 0، 5، 10، …، 55 |
| كل 15 دقيقة | */15 * * * * | الدقيقة 0، 15، 30، 45 |
| كل 30 دقيقة | */30 * * * * | الدقيقة 0 والدقيقة 30 |
| كل ساعة | 0 * * * * | بداية كل ساعة |
| كل ساعتين | 0 */2 * * * | الساعة 0، 2، 4، …، 22 |
| كل 6 ساعات | 0 */6 * * * | الساعة 0، 6، 12، 18 |
| مرتين يوميًا (9 صباحًا و9 مساءً) | 0 9,21 * * * | الدقيقة 0 من الساعتين 9 و21 |
| كل يوم عمل في 9 صباحًا | 0 9 * * 1-5 | الإثنين-الجمعة 09:00 |
| كل عطلة أسبوعية في 9 صباحًا | 0 9 * * 0,6 | السبت والأحد 09:00 |
| يوميًا منتصف الليل | 0 0 * * * | كل يوم 00:00 |
| يوميًا في 2:30 صباحًا | 30 2 * * * | نافذة المعالجة في ساعات انخفاض الحمل |
| كل إثنين في 9 صباحًا | 0 9 * * 1 | الإثنين 09:00 |
| كل جمعة في 5 مساءً | 0 17 * * 5 | الجمعة 17:00 |
| كل أحد منتصف الليل | 0 0 * * 0 | يكافئ @weekly |
| أول الشهر منتصف الليل | 0 0 1 * * | اليوم الأول 00:00 — يكافئ @monthly |
| الخامس عشر من كل شهر ظهرًا | 0 12 15 * * | نافذة الرواتب منتصف الشهر |
| فحص آخر يوم (بغلاف) | 0 0 28-31 * * + سكربت | يتطلب فحص تاريخ |
| ربع سنوي (1 يناير/أبريل/يوليو/أكتوبر) | 0 0 1 JAN,APR,JUL,OCT * | أول يوم من كل ربع |
| سنويًا (1 يناير) | 0 0 1 1 * أو @yearly | منتصف ليل رأس السنة |
| كل 5 دقائق في أيام العمل 9-5 | */5 9-17 * * 1-5 | استطلاع في ساعات العمل |
| كل 30 دقيقة في عطلة الأسبوع | */30 * * * 0,6 | مراقبة السبت/الأحد |
| مرتين في الساعة، 15 و45 | 15,45 * * * * | إزاحة عن زحمة الدقيقة :00 |
| أول إثنين (بغلاف) | 0 9 1-7 * 1 + فحص AND | يحتاج غلافًا (انظر أدناه) |
| الماكرو | @hourly @daily @weekly @monthly @yearly | غير قياسي لكن واسع الدعم |
| عند إعادة الإقلاع فقط | @reboot | غير قياسي، يدعمه vixie cron فقط |
الصق أيًّا من هذه في مولد crontab — منشئ ومحلل تعبير cron لمعاينة المرات الخمس التالية للتشغيل قبل النشر.
شرح صيغة cron — الحقول الخمسة
تعبير cron هو خمسة حقول مفصولة بمسافات بيضاء يليها أمر تنفيذي. كل حقل يتحكم في شريحة من الجدول. هذه هي قاعدة صيغة تعابير cron عبر جميع المُجدوِلات في هذا الدليل.
┌──────────── minute (0 - 59)
│ ┌────────── hour (0 - 23)
│ │ ┌──────── day-of-month (1 - 31)
│ │ │ ┌────── month (1 - 12 or JAN-DEC)
│ │ │ │ ┌──── day-of-week (0 - 6 or SUN-SAT; 0 and 7 both mean Sunday)
│ │ │ │ │
* * * * * command-to-run
الترتيب من اليسار إلى اليمين هو: الدقيقة، الساعة، يوم الشهر، الشهر، يوم الأسبوع. أي من أصغر وحدة إلى أكبر.
القيم المسموحة لكل حقل
| الحقل | المدى | الأسماء البديلة | ملاحظات |
|---|---|---|---|
| الدقيقة | 0-59 | لا يوجد | 0 يعني “عند بداية الساعة” |
| الساعة | 0-23 | لا يوجد | نظام 24 ساعة؛ 0 منتصف الليل، 12 الظهر |
| يوم الشهر | 1-31 | لا يوجد | الأيام غير الصالحة لشهر معين تُهمَل صامتةً (مثل 31 فبراير) |
| الشهر | 1-12 | JAN, FEB, MAR, …, DEC | غير حساس لحالة الأحرف |
| يوم الأسبوع | 0-7 | SUN, MON, TUE, …, SAT | 0 و7 كلاهما يعني الأحد |
المُعامِلات بالتفصيل
خمسة مُعامِلات تُغطِّي كل تعبير cron قياسي:
| المُعامِل | المعنى | مثال | يتوسع إلى |
|---|---|---|---|
* | أي قيمة | * * * * * | كل دقيقة |
, | قائمة | 0 9,12,17 * * * | 09:00، 12:00، 17:00 |
- | مدى شامل | 0 9-17 * * * | كل ساعة من 09:00 إلى 17:00 |
/ | خطوة | */15 * * * * | الدقيقة 0، 15، 30، 45 |
| مختلط | مركب | 0 9-12,14-17 * * * | الصباح + بعد الظهر، تجاوُز الغداء |
مُعامِل الخطوة يحتاج انتباهًا. */N مرتبط بأدنى قيمة في الحقل، لا بالوقت الحالي. */15 يعني “الدقيقة 0، 15، 30، 45 من كل ساعة”، وليس “كل 15 دقيقة من الآن”. إذا حفظتَ التعبير عند 12:03، فالتشغيل التالي عند 12:15. ومع قاعدة غير نجمية، يُقرأ 5/15 على أنه “ابدأ من 5 ثم كل 15 دقيقة”: الدقيقة 5، 20، 35، 50.
الأشهر وأيام الأسبوع بأسمائها
تُكتب الأشهر وأيام الأسبوع كأسماء، وغير حساسة لحالة الأحرف:
0 0 1 JAN,APR,JUL,OCT * # first of each quarter
0 9 * * MON-FRI # weekdays at 9 AM
0 17 * * FRI # Friday at 5 PM
الأسماء أكثر قابلية للقراءة في مراجعة الكود، والصيغ الرقمية أكثر قابلية للنقل قليلًا. الأفضل اختيار أسلوب واحد لكل مشروع.
الماكرو غير القياسي: @reboot و@daily ورفاقهما
معظم تطبيقات cron تقبل ستة اختصارات ماكرو:
| الماكرو | يتوسع إلى | المعنى |
|---|---|---|
@yearly / @annually | 0 0 1 1 * | مرة واحدة سنويًا، 1 يناير منتصف الليل |
@monthly | 0 0 1 * * | أول كل شهر منتصف الليل |
@weekly | 0 0 * * 0 | كل أحد منتصف الليل |
@daily / @midnight | 0 0 * * * | كل يوم منتصف الليل |
@hourly | 0 * * * * | بداية كل ساعة |
@reboot | (خاص) | مرة واحدة عند بدء عفريت cron |
هذه الماكروهات غير قياسية: vixie cron وcronie يدعمانها، لكن Kubernetes CronJob وGitHub Actions وAWS EventBridge لا تدعمها. إن أردت تعابير قابلة للنقل، اكتب الصيغة الخماسية. كما أن @reboot نادرًا ما يعمل داخل الحاويات لأن عفريت cron قد لا يكون عملية init.
50+ تعبير cron جاهز للنسخ (مُجمَّعة بحسب الحالة)
جدول المرجع السريع يُغطِّي الحالات الشائعة، وهذا القسم يقدم ست مجموعات بأمثلة أكثر تفصيلًا لمهام cron.
كل N دقيقة
* * * * * # every minute
*/2 * * * * # every 2 minutes
*/5 * * * * # every 5 minutes — the cron expression every 5 minutes case
*/10 * * * * # every 10 minutes
*/15 * * * * # every 15 minutes
*/30 * * * * # every 30 minutes
0,30 * * * * # explicit minutes 0 and 30 (same as */30)
*/45 * * * * # WARNING: fires at 0 and 45 only, then wraps
*/45 فخ شائع: نطاق الدقيقة 0-59، فيقع التشغيل عند 0 ثم 45 ثم يلتف عند الساعة التالية. للحصول على إيقاع 45 دقيقة فعلي تحتاج عاملًا خارجيًا.
تعابير الساعة
0 * * * * # every hour at :00
30 * * * * # every hour at :30
0 */2 * * * # every 2 hours, even hour
0 */6 * * * # every 6 hours
0 */12 * * * # twice a day at 00:00 and 12:00
15 */2 * * * # every 2 hours, offset by 15 min (avoids :00 spike)
يوميًا في أوقات محددة
0 0 * * * # midnight (= @daily / @midnight)
30 2 * * * # 02:30 — low-traffic batch window
0 9 * * * # 09:00
45 23 * * * # 23:45 — end-of-day rollups
0 9,12,17 * * * # three times daily
0 9-17 * * * # every hour from 09:00 through 17:00
جداول أسبوعية
0 9 * * 1-5 # weekdays at 9 AM
0 9 * * 0,6 # weekends at 9 AM
0 18 * * 5 # Fridays at 6 PM
0 0 * * 0 # Sunday at midnight (= @weekly)
0 9 * * MON,WED,FRI # Mon/Wed/Fri at 9 AM
*/30 9-17 * * 1-5 # every 30 min, business hours, weekdays
شهري وربع سنوي
0 0 1 * * # 1st of month at midnight (= @monthly)
0 0 15 * * # 15th — payroll window
0 0 1,15 * * # 1st and 15th — semi-monthly
0 0 1 */3 * # quarterly: first of Jan, Apr, Jul, Oct
0 0 1 JAN,APR,JUL,OCT * # same, named months
0 0 28-31 * * # last few days — pair with a date-check wrapper
لا يوجد تعبير POSIX أصلي لـ “آخر يوم في الشهر”. شغِّل غلافًا يفحص date -d tomorrow +%d = 01، أو استخدم مُجدوِلًا يدعم ذلك أصلًا (Quartz فيه L؛ Kubernetes لا).
اختصارات سنوية والماكرو
0 0 1 1 * # Jan 1 at midnight (= @yearly / @annually)
0 0 25 12 * # Christmas at midnight
@yearly # = 0 0 1 1 *
@monthly # = 0 0 1 * *
@weekly # = 0 0 * * 0
@daily # = 0 0 * * *
@hourly # = 0 * * * *
@reboot # special: once on daemon start (vixie cron only)
كل هذه التعابير يمكن لصقها في مولد crontab — منشئ ومحلل تعبير cron لمعاينة المرات الخمس التالية قبل النشر.
cron مقابل مؤقتات systemd ومُجدوِلات السحاب — مصفوفة قرار
cron هو الخيار الافتراضي، وليس الأمثل دائمًا. الجدول التالي يقارن سبعة مُجدوِلات شائعة، وهو مفيد لاختيار cron أو مؤقت systemd أو Kubernetes CronJob أو Vercel cron، أو للانتقال من crontab إلى السحاب المُدار.
| الميزة | vixie cron | مؤقت systemd | K8s CronJob | GHA schedule | AWS EventBridge | Vercel Cron | Cloudflare Workers |
|---|---|---|---|---|---|---|---|
| صيغة الحقول | POSIX 5 حقول | مواصفة OnCalendar | POSIX 5 + timeZone | POSIX 5 حقول | Quartz 6 حقول مع ? | POSIX 5 حقول | POSIX 5 حقول |
| أقل فاصل | دقيقة واحدة | ثانية واحدة | دقيقة واحدة | بأفضل جهد، يُنصح ≥ 15 دقيقة | دقيقة واحدة | دقيقة واحدة (خطة Pro) | دقيقة واحدة |
| منطقة زمنية صريحة | CRON_TZ= | Persistent=true | spec.timeZone (1.27+) | UTC فقط | ScheduleExpressionTimezone | UTC فقط | UTC فقط |
| استرجاع المهام الفائتة | لا (استخدم anacron) | نعم (Persistent=true) | نعم (startingDeadlineSeconds) | لا | نعم | لا | لا |
| إعادة المحاولة / التراجع | لا | جزئي | نعم (backoffLimit) | إعادة عند الفشل | نعم | لا | نعم |
| التحكم في التزامن | لا (استخدم flock) | جزئي | نعم (concurrencyPolicy) | لا | لا | لا | لا |
دعم @reboot | نعم | نعم (عبر OnBootSec=) | لا | لا | لا | لا | لا |
مؤقتات systemd — متى تُفضَّل على cron
على Linux المبني على systemd، تُعدّ المؤقتات بديلًا جادًّا: صيغة تقويم قابلة للقراءة، وتكامل مع السجل journal، واسترجاع للمهام الفائتة. هذا مثال على مؤقت وخدمة مقابلة له:
# daily-report.timer
[Unit]
Description=Run daily report at 9 AM
[Timer]
OnCalendar=*-*-* 09:00:00
Persistent=true
Unit=daily-report.service
[Install]
WantedBy=timers.target
# daily-report.service
[Unit]
Description=Daily report job
[Service]
Type=oneshot
ExecStart=/usr/local/bin/daily-report.sh
User=reporter
فعِّل بـ systemctl enable --now daily-report.timer. الميزة الفارقة هي Persistent=true: لو كان الجهاز مُطفأً عند 9 صباحًا، ينطلق المؤقت بمجرد الإقلاع، ولا مقابل لذلك في vixie cron دون anacron. لتقوية الخدمات، راجع أفضل ممارسات الأمان.
Kubernetes CronJob
يُغلِّف Kubernetes جدول POSIX بأدوات للتحكم في التزامن والسجل وضبط المنطقة الزمنية صراحةً:
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-report
spec:
schedule: "0 2 * * *"
timeZone: "America/New_York" # Kubernetes 1.27+
concurrencyPolicy: Forbid # never run two at once
startingDeadlineSeconds: 300 # skip if delayed >5 min
jobTemplate:
spec:
backoffLimit: 2
template:
spec:
restartPolicy: OnFailure
containers:
- name: reporter
image: reporter:1.4.0
command: ["/usr/local/bin/report.sh"]
concurrencyPolicy: Forbid هو مكافئ flock هنا. بدونه، تتراكم المهمة الطويلة مع خلفها. راجع قسم مرجع حقول Kubernetes CronJob لبقية الإعدادات.
تحفظات جدولة GitHub Actions
GitHub Actions يقبل POSIX cron القياسي ذا الخمسة حقول:
on:
schedule:
- cron: '0 9 * * 1-5' # weekdays at 9 AM UTC
الجدول هنا “بأفضل جهد”: تحت الحمل العالي على عُمَّال GitHub، قد تتأخر المهام دقائق أو تُتجاوز كليًّا. تجنب الفواصل الأقل من 15 دقيقة. لا توجد إعدادات منطقة زمنية، فالتشغيل دائمًا بـ UTC.
AWS EventBridge — صيغة Quartz بستة حقول
يستخدم AWS EventBridge صيغة cron بنكهة Quartz مع ستة حقول، ويُطلب ? في أحد حقلَي اليوم:
cron(0 9 * * ? *)
ترتيب الحقول: Minutes Hours Day-of-month Month Day-of-week Year. يجب أن يكون أحد حقلَي اليوم ? عندما يكون الآخر مُقيَّدًا، وهي طريقة Quartz لحلّ التباس OR في POSIX. لذا فإن النسخ المباشر من Linux crontab يفشل في التحقق.
Vercel Cron وCloudflare Workers وRender Cron Jobs
المنصات الحديثة بلا خادم تتوحد على POSIX ذي الخمسة حقول. تُحدَّد مهمة Vercel cron داخل vercel.json على شكل { "crons": [{ "path": "/api/cron/nightly", "schedule": "0 2 * * *" }] }. أما مُحفِّزات Cloudflare Workers Cron فتُكتب في wrangler.toml:
[triggers]
crons = ["*/15 * * * *", "0 9 * * 1-5"]
ويستخدم Render ملف render.yaml. والثلاثة جميعًا تعمل بـ UTC دون تجاوز للمنطقة الزمنية لكل جدول، لذا يُفضَّل التصميم بـ UTC منذ البداية.
7 فخاخ في تصحيح cron (وكيف تُمسك بها)
تعود معظم تقارير “مهمة cron لا تعمل” إلى أحد سبعة أسباب جذرية. ينبغي مراجعة هذه القائمة قبل توجيه اللوم إلى المُجدوِل.
الفخ 1: PATH ضئيل
يبدأ cron المهام بـ $PATH ضئيل، عادةً /usr/bin:/bin. صدفتك التفاعلية تحتوي على /usr/local/bin و~/.cargo/bin وعشرات الإدخالات في .bashrc، لكن لا شيء منها موجود في cron. هذه أكثر مشاكل بيئة المسار شيوعًا عند تصحيح cron.
العَرَض الشائع: node: command not found. الحل: اضبط PATH في أعلى crontab، أو استخدم مسارات مطلقة.
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin
*/15 * * * * /usr/local/bin/poll-api.sh
0 9 * * * /home/deploy/.cargo/bin/my-rust-cli
الفخ 2: ضياع stdout وstderr صامتةً
افتراضيًا، يذهب خرج cron إلى صندوق بريد لا يقرأه أحد، وتفشل المهمة بصمت. أعِد توجيه الجدولين:
*/15 * * * * /usr/local/bin/job.sh >> /var/log/job.log 2>&1
لخرج JSON، مرِّره عبر jq. ولاستخراج أسطر السجل، راجع مرجع التعابير النمطية. أما مع مؤقتات systemd، فإن journalctl -u your-timer.service يلتقط الخرج.
الفخ 3: انجراف المنطقة الزمنية بين التطوير والإنتاج
كتبتَ 0 9 * * * على حاسبك في نيويورك متوقعًا 9 صباحًا بالتوقيت الشرقي، لكن الخادم يعمل بـ UTC. ينطلق cron في 9 صباحًا UTC، أي 4 صباحًا بالتوقيت الشرقي، قبل أن ينتبه أحد. الحل: اضبط الخوادم على UTC واكتب الجداول بـ UTC، أو ثبِّت المنطقة الزمنية صراحةً.
CRON_TZ=America/New_York
0 9 * * * /usr/local/bin/morning-report.sh
يعمل CRON_TZ في vixie cron 3.0+، ويدعم Kubernetes 1.27+ الحقل spec.timeZone، ويدعم AWS EventBridge الحقل ScheduleExpressionTimezone، أما GitHub Actions فيعمل دائمًا بـ UTC. لتفاصيل UTC والتوقيت الصيفي وحسابات epoch، راجع دليل طوابع زمن Unix.
الفخ 4: % غير مُهرَّب في الأوامر
يُعامِل cron % غير المُهرَّبة على أنها أسطر جديدة، وتُدفع بقية السطر إلى الأمر كـ stdin. لذا date +"%Y-%m-%d" يفشل. هرِّب كل % بـ \%، أو انقل المنطق إلى سكربت:
0 0 * * * echo "Run at $(date +"\%Y-\%m-\%d")" >> /tmp/log
الفخ 5: التشغيلات المتداخلة
مهمة */5 * * * * تستغرق أحيانًا سبع دقائق، فتبدأ النسخة التالية قبل انتهاء السابقة. تتصارع نسختان على الصف نفسه وملف القفل نفسه وحصة API نفسها. سلسِلها بـ flock:
*/5 * * * * flock -n /tmp/job.lock /usr/local/bin/job.sh
-n يخرج فورًا إذا كان القفل محجوزًا. في Kubernetes، اضبط concurrencyPolicy: Forbid. أذونات ملف القفل مهمة، فراجع أفضل ممارسات الأمان.
الفخ 6: @reboot داخل الحاويات
@reboot يُشغَّل مرة واحدة عند بدء عفريت cron. في الجهاز الافتراضي يقابل ذلك الإقلاع. أما في الحاوية، فعفريت cron ليس PID 1 عادةً وقد لا يعمل أصلًا. لذا تجنب @reboot في الحاويات، وضع منطق التشغيل لمرة واحدة عند الإقلاع في نقطة الدخول entrypoint أو في حاوية تهيئة init container.
الفخ 7: دلالات OR ليوم الشهر/يوم الأسبوع في POSIX
هذا أكثر فخ في cron كلفةً. قاعدة POSIX: عندما يكون كلٌّ من يوم الشهر ويوم الأسبوع مُقيَّدًا (أي ليس *)، ينطلق الجدول حين يُطابق أيٌّ منهما.
يبدو 0 0 1 * 5 أنه “منتصف ليل اليوم الأول، فقط في الجمعة”، لكنه ينطلق في اليوم الأول وفي كل جمعة: من 6 إلى 10 تشغيلات إضافية في الشهر.
# WRONG: looks like "1st of the month, only if Friday"
0 0 1 * 5
# RIGHT: pick one constraint
0 0 1 * * # every 1st of the month
0 0 * * 5 # every Friday
# AND semantics need a wrapper
0 0 1-7 * 5 [ "$(date +\%u)" = "5" ] && /script # first Friday only
الصق التعابير المشبوهة في مولد crontab — منشئ ومحلل تعبير cron، فمعاينة التشغيل التالي تُظهر فخ OR بوضوح.
المُجدوِلات الحديثة — متى لا تستخدم cron
cron مناسب لـ “نفِّذ هذا الأمر تقريبًا في هذا الوقت، بإيقاع ثابت”، لكنه غير مناسب لعدة مشاكل مجاورة:
- سير عمل بتبعيات (شغِّل A، ثم B إذا نجح A) ← Airflow وPrefect وDagster.
- إعادة المحاولة، التراجع الأُسي، طوابير الرسائل الميتة ← Temporal وAWS Step Functions وSidekiq.
- فواصل أقل من دقيقة ← عامل طويل العمر ينام بين التكرارات.
- توقيت بدقة الثانية ← عفريت مخصص؛ المُجدوِلات المُدارة تتبرأ من التوقيت الدقيق.
- العمل المُحرَّك بالأحداث ← webhooks وطوابير الرسائل وتدفقات change-data-capture.
لا يختفي cron تمامًا. Airflow وStep Functions وSidekiq كلها تقبل تعابير cron لنقطة دخول سير العمل، فالقواعد ذات الحقول الخمسة قابلة لإعادة الاستخدام.
مرجع حقول Kubernetes CronJob
أظهرت مصفوفة القرار أعلاه CronJob مُبسَّطًا، وفيما يلي المرجع الكامل لصيغة kubernetes cronjob:
| الحقل | الافتراضي | ما يفعله |
|---|---|---|
schedule | مطلوب | تعبير POSIX cron بخمسة حقول |
timeZone | منطقة المتحكم | منطقة زمنية صريحة (1.27+)؛ استخدم أسماء IANA |
concurrencyPolicy | Allow | Forbid يتجاوز التشغيل الجديد ما دام السابق نشطًا؛ Replace يُلغي السابق |
startingDeadlineSeconds | بلا حد | تجاوز إذا تأخر أكثر من هذه القيمة |
successfulJobsHistoryLimit | 3 | عدد المهام الناجحة المحفوظة |
failedJobsHistoryLimit | 1 | عدد المهام الفاشلة المحفوظة |
suspend | false | إيقاف مؤقت دون حذف |
backoffLimit | 6 | إعادة محاولات Pod قبل وَسم المهمة بالفشل |
activeDeadlineSeconds | غير مضبوط | حد صلب لزمن تشغيل Pod |
ttlSecondsAfterFinished | غير مضبوط | حذف تلقائي للمهمة بعد هذه الثواني |
فخان شائعان: الأول، نسيان timeZone يجعل الجدول يتبع منطقة مُضيف kube-controller-manager وهي غير متوقعة في Kubernetes المُدار. والثاني، مع جدول من دقيقة واحدة، تتراكم ثلاثة كائنات مهام في الدقيقة بسبب القيمة الافتراضية successfulJobsHistoryLimit: 3 ما لم تُضبط ttlSecondsAfterFinished.
مكافئات cron عبر المنصات
macOS launchd. تنصح Apple بـ launchd بدلًا من cron. مهمة launchd هي ملف .plist داخل ~/Library/LaunchAgents/:
<plist version="1.0"><dict>
<key>Label</key><string>com.example.daily</string>
<key>ProgramArguments</key><array><string>/usr/local/bin/daily.sh</string></array>
<key>StartCalendarInterval</key>
<dict><key>Hour</key><integer>9</integer><key>Minute</key><integer>0</integer></dict>
</dict></plist>
حمِّل بـ launchctl load ~/Library/LaunchAgents/com.example.daily.plist. وعلى عكس cron، يلتقط launchd التشغيلات الفائتة بعد النوم والاستيقاظ.
جدول مهام Windows يستخدم schtasks:
schtasks /create /tn "DailyReport" /tr "C:\scripts\report.bat" /sc DAILY /st 09:00
schtasks /create /tn "EveryFifteen" /tr "C:\scripts\poll.bat" /sc MINUTE /mo 15
على WSL، يعمل Linux cron الأصلي لكنه يتوقف عند انتهاء الجلسة، لذا استخدم جدول مهام Windows لتشغيل مهام WSL الدائمة.
cron داخل حاويات Docker. معظم الصور الرشيقة (alpine، debian-slim، distroless) تُشحن بلا عفريت cron. ثبِّت cronie أو busybox-cron وشغِّله كـ PID 1 عبر tini أو s6-overlay، أو استخدم Kubernetes CronJob وهو في الغالب الخيار الأفضل.
نصائح وأنماط متقدمة
آخر يوم في الشهر
لا يوجد في cron مُعامِل أصلي لـ “آخر يوم”. شغِّل المهمة كل يوم في النافذة 28-31 وافحص إن كان الغد هو اليوم الأول:
0 23 28-31 * * [ "$(date -d tomorrow +\%d)" = "01" ] && /usr/local/bin/eom.sh
اليوم الـ N من الأسبوع في الشهر
يستخدم “أول إثنين” نمط الغلاف نفسه: قيِّد الأيام إلى 1-7، ثم افحص يوم الأسبوع:
0 9 1-7 * * [ "$(date +\%u)" = "1" ] && /usr/local/bin/first-monday.sh
لـ “آخر جمعة”، استخدم الأيام 25-31 مع فحص يوم الأسبوع.
إزاحة عشوائية لتوزيع الحمل
عندما تُشغِّل عدة أجهزة cron نفسه، يُولِّد 0 0 * * * اندفاعًا متزامنًا عند منتصف ليل UTC. أضف تأخيرًا عشوائيًا:
RANDOM_DELAY=10 # cronie / anacron, in minutes
0 0 * * * /usr/local/bin/job.sh
0 0 * * * sleep $((RANDOM \% 600)); /usr/local/bin/job.sh # portable
مراقبة نبضات القلب
يفشل cron بصمت. نمط “مفتاح الميت” يعمل هكذا: ترسل المهمة ping إلى خدمة مراقبة بعد كل تشغيل ناجح، وتُنبِّه الخدمة عند عدم وصول ping متوقع. Healthchecks.io وCronitor وDead Man’s Snitch تُقدِّم طبقات مجانية.
*/15 * * * * /usr/local/bin/job.sh && curl -fsS --retry 3 https://hc-ping.com/your-uuid
ولمنطق مراقبة يتفرع على أكواد الاستجابة (200 سليم، 429 محدود المعدل، 503 متدهور)، راجع مرجع رموز حالة HTTP.
الإيدمبوتنسية خاصية المهمة لا المُجدوِل
لا يوفر cron إعادة محاولة، ولا استرجاعًا للمهام الفائتة، ولا تحكمًا في التزامن. الحل الأكثر متانة هو جعل المهمة نفسها آمنة للتشغيل عدة مرات. بدلًا من “أرسل تقرير اليوم في 9 صباحًا”، صمِّمها على شكل “أرسل تقرير اليوم إن لم يُرسل بعد”، فحينئذٍ تتقارب التشغيلات الفائتة والمكررات إلى الحالة نفسها.
الأسئلة الشائعة
هل */5 * * * * حقًّا كل 5 دقائق؟
تقريبًا — */5 * * * * مرتبط بالدقيقة 0، لا بـ “كل 5 دقائق من الآن”. ينطلق عند الدقيقة 0، 5، 10، …، 55 من كل ساعة. الخطوة */N نسبية لأدنى قيمة في الحقل، لا للوقت الحالي. إذا حفظتَه عند 12:03 يصبح التشغيل التالي عند 12:05، لا عند 12:08.
ماذا يعني 0 0 * * * في cron؟
0 0 * * * يعني كل يوم منتصف الليل (00:00) في المنطقة الزمنية المحلية للخادم. الحقول: الدقيقة 0، الساعة 0، أي يوم من الشهر، أي شهر، أي يوم من الأسبوع. وهو يكافئ الماكرو @daily أو @midnight. لتثبيت المنطقة الزمنية، أضف CRON_TZ=America/New_York في أعلى crontab.
كيف أُشغِّل مهمة cron كل 30 ثانية؟
لا يمكنك ذلك بـ POSIX cron القياسي، لأن أقل دقة فيه دقيقة واحدة. هناك ثلاث حلول: مهمتان متعاقبتان عند * * * * * مع sleep 30 && على إحداهما، أو مؤقت systemd بـ OnCalendar=*:*:0/30، أو عامل طويل العمر ينام بين التكرارات. الأخير عادةً هو الصواب.
ما المنطقة الزمنية التي يستخدمها cron افتراضيًا؟
منطقة النظام المحلية للخادم (/etc/timezone أو متغير البيئة TZ). مهمة 9 صباحًا على خادم UTC تنطلق عند 4 صباحًا بالتوقيت الشرقي الأمريكي. الحل: اضبط CRON_TZ= في أعلى crontab، أو اضبط الخوادم على UTC وصمِّم الجداول بـ UTC. أما GitHub Actions فيعمل دائمًا بـ UTC، ويدعم Kubernetes 1.27+ الحقل spec.timeZone.
لماذا لا تعمل مهمة cron لديّ؟
إذا كانت مهمة cron لا تعمل، افحص بهذا الترتيب: هل عفريت cron يعمل (systemctl status cron)؟ هل $PATH مضبوط في crontab؟ هل تُلتقط stderr (>> log 2>&1)؟ هل crontab المستخدم مُحمَّل (crontab -l)؟ هل % مُهرَّب في الأوامر؟ هل المنطقة الزمنية كما تتوقع؟ معظم تقارير “لا تعمل” تعود إلى البند الثاني أو الثالث.
هل صيغة Kubernetes CronJob هي نفسها Linux cron؟
نعم في حقل الجدول، فكلاهما يستخدم POSIX ذا الخمسة حقول. ويُضيف Kubernetes الحقل spec.timeZone (1.27+)، والحقل concurrencyPolicy للتحكم في التداخل، والحقل startingDeadlineSeconds لاسترجاع المهام الفائتة، والحقل suspend: true للإيقاف المؤقت. لا شيء من هذا في Linux cron، والبديل هو اللجوء إلى flock وanacron.
ما الفرق بين @reboot و@daily؟
@daily ماكرو لـ 0 0 * * *، أي كل يوم منتصف الليل على جدول ثابت. أما @reboot فيُشغَّل مرة واحدة عند بدء عفريت cron، بلا جدول متكرر. وهو مدعوم في vixie cron وcronie لكن ليس في Kubernetes CronJob أو GitHub Actions أو AWS EventBridge. وفي الحاويات نادرًا ما ينطلق @reboot.
ما الفرق بين cron و crontab؟
cron هو الـ daemon في الخلفية الذي يشغّل المهام المجدولة، و crontab هو الملف الذي يسرد هذه المهام (وأيضاً أمر crontab لتحرير الملف). يقرأ الـ daemon جدول كل مستخدم في دورة منتظمة وينفّذ الأوامر التي يتطابق وقت تنفيذها مع تعبير cron. باختصار: cron هو المحرّك، و crontab هو الوصفة.