آپ کی cron job کیوں نہیں چلتی؟ 5 عام وجوہات
cron job نہ چلنے کی 5 وجوہات جانیں: محدود PATH، unescaped percent sign، غلط crontab، mail میں چھپا output، اور shell فرض کرنے والی script۔
آپ کی cron job کیوں نہیں چلتی
جو cron job “کبھی نہیں چلتی” دکھائی دیتی ہے، وہ تقریباً ہمیشہ چل چکی ہوتی ہے۔ وہ ایسے environment میں چلی ہوتی ہے جو آپ کے shell سے مختلف ہوتا ہے، پہلے ہی لمحے میں fail ہو جاتی ہے، اور اس کا پیغام ایسی جگہ چلا جاتا ہے جہاں آپ اسے نہیں پڑھ رہے ہوتے۔ تقریباً ہر رپورٹ کی وضاحت یہ پانچ وجوہات کرتی ہیں: search path، percent sign، غلط crontab file، mail پر بھیجا گیا output، اور ایسی script جو login session کی توقع کرتی ہے۔
cron ایک daemon یعنی background service ہے جو crontab files پڑھتا ہے اور schedule کے مطابق commands شروع کرتا ہے۔ یہ آپ کا .bashrc نہیں پڑھتا، terminal نہیں کھولتا، login shell شروع نہیں کرتا، اور command fail ہونے پر آپ کو اطلاع نہیں دیتا۔ ذیل کی ہر وجہ انہی چار حقائق سے پیدا ہوتی ہے۔
ان وجوہات کو اسی ترتیب سے دیکھیں، اور سب سے پہلے اس بنیادی سوال کا جواب دیں: کیا cron نے واقعی job شروع کی تھی؟ “cron نے job کبھی شروع نہیں کی” اور “job شروع ہوئی اور ختم ہو گئی” دو مختلف مسائل ہیں، جن میں کوئی مشترک وجہ نہیں ہوتی۔ اس لیے پہلے اسی سوال کا جواب دیں۔
کیا cron نے بالکل کام کیا؟
مختلف distribution families میں daemon کا unit name مختلف ہوتا ہے۔ دونوں نام check کریں، پھر log پڑھیں۔
systemctl status cron
systemctl status crond
journalctl -u cron --since "2 hours ago"
journalctl -u crond --since "2 hours ago"Debian اور Ubuntu اس unit کو cron کہتے ہیں۔ Fedora، Rocky اور Alma اسے crond کہتے ہیں۔ کسی مشین پر ان دونوں میں سے صرف ایک نام موجود ہوتا ہے، اس لیے دونوں commands میں سے ایک کا unknown unit رپورٹ کرنا معمول ہے اور خرابی نہیں۔
اپنے system کی لکھی ہوئی entries پڑھیں۔ کسی guide سے نقل کی گئی line تلاش نہ کریں، کیونکہ wording مختلف cron implementations اور logging setups میں بدل جاتی ہے۔ آپ کو صرف دو چیزیں check کرنی ہیں: کیا آپ کے schedule میں دیے گئے minute پر کوئی entry موجود ہے، اور کیا اس entry میں آپ کی command کا نام ہے۔ آپ کی command کا نام دینے والی entry کا مطلب ہے کہ cron نے اپنا کام کر دیا اور خرابی command کے اندر ہے۔ بالکل کوئی entry نہ ہونا اس بات کی علامت ہے کہ cron کے پاس آپ کا schedule موجود ہی نہیں تھا؛ یہ نیچے دی گئی وجہ 3 ہے۔
کچھ images cron messages کو rsyslog کے ذریعے journal کے بجائے ایک file میں بھیجتی ہیں۔ /var/log میں cron یا syslog کے نام والی file تلاش کریں، پھر اس کا آخری حصہ پڑھیں۔
ls -l /var/log
sudo tail -n 50 /var/log/syslogاگر unit اور log دونوں موجود نہ ہوں تو ممکن ہے کہ cron installed ہی نہ ہو۔ Minimal cloud images اور containers میں اکثر یہ شامل نہیں ہوتا۔
dpkg -l cron
rpm -q cronie
sudo apt install cron
sudo dnf install cronie
sudo systemctl enable --now cronوجہ 1: cron کے پاس آپ کا PATH نہیں ہوتا
آپ کا interactive shell PATH کو /etc/profile، ~/.profile، ~/.bashrc اور ان فائلوں سے source ہونے والی تمام فائلوں سے تیار کرتا ہے۔ cron job کے لیے یہ عمل نہیں ہوتا۔ cron command کو اپنے مختصر environment کے ساتھ شروع کرتا ہے، اس لیے standard system directories کے باہر موجود program نہیں ملتا۔ /usr/local/bin، /opt کے اندر موجود کوئی بھی چیز، language version manager، Python virtual environment یا Go workspace اس مسئلے کا ممکنہ سبب ہو سکتا ہے۔ job اپنی پہلی line پر fail ہو جاتی ہے، اور shell "not found" طرز کا error لکھتا ہے۔ اس error کے درست الفاظ اس shell پر منحصر ہوتے ہیں جس نے اسے چلایا۔
آپ کی job میں استعمال ہونے والی ہر command کا اصل path معلوم کریں۔
command -v docker
command -v node
readlink -f "$(command -v node)"پھر یا تو job میں یہ absolute paths لکھیں، یا crontab کے شروع میں ایک مرتبہ PATH مقرر کریں۔
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 3 * * * /usr/local/bin/mytool runیہ فہرست اپنی مشین سے echo "$PATH" کے ذریعے حاصل کریں اور وہ چیزیں نکال دیں جو صرف interactive session کے اندر موجود ہوتی ہیں۔ یہاں ایک اصول اہم ہے: cron ان assignment lines میں variables کو expand نہیں کرتا۔ PATH=$PATH:/usr/local/bin میں literal text $PATH:/usr/local/bin محفوظ ہوتا ہے، اس لیے job کو ایسا search path ملتا ہے جس میں کوئی قابلِ استعمال directory نہیں ہوتی۔ پوری فہرست واضح طور پر لکھیں۔
Version manager کے لیے صرف path کافی نہیں ہوتا۔ nvm، pyenv، rbenv اور asdf آپ کے .bashrc سے shell function یا shims directory install کرتے ہیں، لیکن cron اس فائل کو کبھی نہیں پڑھتا۔ Versioned binary کو absolute path کے ذریعے چلائیں، یا اپنی script کی پہلی line کے طور پر manager کی init script کو source کریں۔
وجہ 2: percent sign آپ کی command ختم کرتا ہے
crontab کے command field میں % عام character نہیں ہے۔ پہلا unescaped % command ختم کر دیتا ہے۔ اس کے بعد موجود تمام متن command کو standard input کے طور پر دیا جاتا ہے، اور ہر مزید % newline بن جاتا ہے۔ یہ کسی program کو مختصر input دینے کے لیے cron کا حقیقی feature ہے، اور اسی وجہ سے date-stamped filename والی entry crontab کی عام خراب configuration بنتی ہے۔
0 3 * * * /usr/bin/tar -czf /srv/backups/site-$(date +%F).tar.gz /srv/site لکھنے پر tar کو formatted date کبھی نہیں ملتی۔ cron پہلی % پر line کاٹ دیتا ہے، اس لیے shell کو نامکمل command substitution ملتی ہے اور آپ کی line کا باقی حصہ standard input کے طور پر پہنچتا ہے۔ ہر percent sign سے پہلے backslash لگائیں۔
0 3 * * * /usr/bin/tar -czf /srv/backups/site-$(date +\%F).tar.gz /srv/siteاس ایک line کو دو layers باری باری پڑھتی ہیں۔ \% ایک cron rule ہے، جسے cron کوئی بھی چیز شروع کرنے سے پہلے apply کرتا ہے۔ $(date +\%F) command substitution ہے، جسے بعد میں cron کی شروع کردہ shell apply کرتی ہے۔ کون سا character کس layer کے اختیار میں ہے، یہ سمجھنا ہی اصل نکتہ ہے۔
زیادہ محفوظ طریقہ یہ ہے کہ logic کو crontab سے مکمل طور پر باہر رکھا جائے۔ اسے ایک script میں رکھیں، جہاں percent sign کا کوئی special meaning نہیں ہوتا۔
#!/bin/bash
set -euo pipefail
stamp="$(date +%F)"
tar -czf "/srv/backups/site-${stamp}.tar.gz" /srv/siteاس کے بعد crontab line میں صرف ایک path اور redirect رہتا ہے۔ جس crontab کو آپ ایک نظر میں پڑھ سکیں، اسے debug کرنا بھی آسان ہوتا ہے۔
وجہ 3: آپ نے کون سا crontab ترمیم کیا؟
کوئی واحد crontab نہیں ہوتا۔ کئی فائلیں ہوتی ہیں، جن کے مالکان اور field counts مختلف ہوتے ہیں، اور غلط فائل میں لکھا گیا job نظر ہی نہیں آتا۔
crontab -eاس صارف کا crontab ترمیم کرتا ہے جو یہ command چلاتا ہے۔sudo crontab -eroot کا crontab ترمیم کرتا ہے۔ ایک ہی server کی troubleshooting کرنے والے دو افراد اکثر دو مختلف فائلیں پڑھ رہے ہوتے ہیں۔sudo crontab -l -u deployکسی دوسرے صارف کا crontab دکھاتا ہے۔ اس سے تصدیق ہوتی ہے کہ job چلانے والے account کے لیے حقیقت میں کیا install ہے۔/etc/crontabاور/etc/cron.dمیں موجود ہر فائل schedule اور command کے درمیان ایک اضافی field رکھتی ہے: وہ user جس کے طور پر job چلانی ہے۔ پانچ fields والی user crontab line کو/etc/cron.dمیں paste کریں تو command کا پہلا لفظ username سمجھا جاتا ہے۔/etc/cron.dمیں موجود فائلوں کے نام صرف letters، digits، underscores اور hyphens پر مشتمل ہونے چاہئیں۔backup.shیاsite.confنام کی فائل صرف اپنے نام کی وجہ سے skip ہو جاتی ہے۔ اس کا نامbackupرکھیں اور log دوبارہ چیک کریں۔/etc/cron.dمیں موجود فائلوں کا مالک root ہونا چاہیے، اور group یا others کے لیے ان میں write permission نہیں ہونی چاہیے۔ls -l /etc/cron.dدونوں باتیں ایک ساتھ دکھاتا ہے۔/etc/cron.dailyاور اس جیسی دوسری directories میں رکھی گئی scripts بھی یہی naming rule follow کرتی ہیں اور ان پر execute bit بھی ہونا چاہیے۔ execute bit نہ ہونے پر فائل خاموشی سے skip ہو جاتی ہے۔/etc/cron.allowاور/etc/cron.denyطے کرتے ہیں کہ کون crontab install کر سکتا ہے۔ اگر ان میں سے کوئی فائل آپ کے server پر موجود ہو تو یہ فرض کرنے سے پہلے اسے پڑھیں کہ آپ کے user کو crontab کی اجازت ہے۔
User crontab install کرنے کے لیے spool file کو ہاتھ سے ترمیم کرنے کے بجائے crontab command استعمال کریں، کیونکہ crontab install کرنے سے پہلے فائل parse کرتا ہے۔ Save کرنے کے بعد command کی واپس دکھائی گئی output پڑھیں۔ اگر یہ فائل مسترد کر دے تو پچھلا version فعال رہتا ہے اور آپ کی تبدیلی لاگو نہیں ہوتی۔ یہ صورت بالکل ایسی لگتی ہے جیسے cron آپ کو نظرانداز کر رہا ہو۔
مالک permissions بھی طے کرتا ہے۔ root کے crontab میں موجود job ایسی files بناتا ہے جن کا مالک root ہوتا ہے، اور انہیں پڑھنے والی application شاید ان میں write نہ کر سکے۔ عام user کے crontab میں موجود job root-only directory نہیں پڑھ سکتا۔ مالک کو کام کے مطابق منتخب کریں: application maintenance اسی application کے اپنے account کے تحت ہونی چاہیے۔ اسی اصول کی بنیاد WordPress wp-cron کو system cron job سے بدلنا ہے۔ Job کی بنائی ہوئی files کا mode اسے وراثت میں ملنے والے umask سے آتا ہے، اور یہ value آپ کے shell کے umask سے مختلف ہو سکتی ہے۔ اس لیے اگر job کی output ناقابلِ مطالعہ ہو تو umask فائل permissions کیسے مقرر کرتا ہے پڑھنا مفید ہے۔
وجہ 4: آؤٹ پٹ ایسے میل باکس میں گئی جسے کوئی نہیں پڑھتا
cron ہر وہ چیز جمع کرتا ہے جو کوئی job standard output اور standard error پر لکھتی ہے۔ اگر job نے کچھ بھی لکھا ہو تو cron وہ متن local mail system کو بھیجتا ہے۔ یہ متن crontab کے مالک کے نام یا اس نام پر بھیجا جاتا ہے جسے MAILTO متعین کرتا ہے۔ محدود configuration والے VPS پر عموماً کوئی MTA (mail transfer agent) نصب نہیں ہوتا، اس لیے یہ متن کہیں deliver نہیں ہوتا۔ آپ کی error کچھ لمحوں کے لیے موجود رہی اور پھر ضائع ہو گئی۔ broken job کے خاموش دکھائی دینے کی یہی مکمل وجہ ہے۔
آؤٹ پٹ کو ایسی file میں بھیجیں جسے آپ control کرتے ہوں۔
0 3 * * * /usr/local/sbin/backup-site.sh >> /var/log/backup-site.log 2>&1>> standard output کو file کے آخر میں شامل کرتا ہے۔ 2>&1 standard error کو اس جگہ بھیجتا ہے جہاں اس وقت standard output جا رہا ہوتا ہے، اس لیے اسے redirect کے بعد لکھنا ضروری ہے۔ اگر ترتیب الٹ ہو، یعنی 2>&1 >> file، تو standard error اپنی اصل destination پر ہی رہتا ہے، اور جس error کو آپ تلاش کر رہے ہیں وہ عین وہی حصہ ہے جو file تک نہیں پہنچتا۔
journal ایک اور موزوں destination ہے۔ logger آپ کے منتخب کردہ tag کے تحت syslog میں لکھتا ہے۔
0 3 * * * /usr/local/sbin/backup-site.sh 2>&1 | logger -t backup-sitejournalctl -t backup-site سے اسے دوبارہ پڑھیں۔ اس طرح job کا اپنا output cron entries کے ساتھ ہی محفوظ رہتا ہے، اور timeline کو follow کرنا آسان ہوتا ہے۔ اگر آپ کو یہ record بھی درکار ہو کہ server پر کس شخص نے کون سا command چلایا، تو یہ الگ system ہے، اور اپنے server پر user commands کی auditing میں اس کی وضاحت موجود ہے۔
crontab کے اوپر MAILTO="" لکھنے سے اس کے نیچے موجود jobs کے لیے mail بند ہو جاتی ہے۔ MAILTO کو حقیقی address پر set کرنا صرف اس صورت میں مفید ہے جب working MTA موجود ہو، اس لیے اس پر انحصار کرنے سے پہلے ثابت کریں کہ mail server سے باہر deliver ہو رہی ہے۔
debugging کے دوران ایک اصول یاد رکھیں: کبھی > /dev/null 2>&1 append نہ کریں۔ یہ ہر crontab کی سب سے عام line ہے، اور آپ کے پاس موجود واحد evidence ضائع کر دیتی ہے۔ job کے کام کرنے کے بعد، اگر چاہیں تو اسے دوبارہ شامل کر دیں۔
وجہ 5: اسکرپٹ ایسے environment کی فرض کرتا ہے جو cron اسے فراہم نہیں کرتا
جب command مل جائے اور اس کا output محفوظ ہو جائے، تو باقی وہ تمام چیزیں ہیں جو آپ کا session آپ کو خود بخود فراہم کرتا ہے۔
- shell لازماً bash نہیں ہوتی۔
ls -l /bin/shسے جانچ کریں۔ Debian اور Ubuntu پر یہ dash کی طرف اشارہ کرتی ہے، اس لیے double bracket test، arrays اورsourcesyntax error کے ساتھ fail ہو جاتے ہیں۔ اسکرپٹ میں#!/bin/bashline شامل کرکے اسکرپٹ کو call کریں، یا crontab کے شروع میںSHELLمقرر کریں۔ - working directory وہ نہیں ہوتی جہاں آپ موجود تھے۔ ہر جگہ absolute paths استعمال کریں، یا اسکرپٹ کی پہلی line میں
cdکے ذریعے directory تبدیل کریں۔ relative path اس عام وجہ میں سب سے نمایاں ہے کہ job "اس وقت چل جاتی ہے جب میں اسے خود چلاتا ہوں"۔ - locale آپ کے session والی نہیں ہوتی۔ جو بھی چیز date یا number کو format کرتی ہو، یا text کو sort کرتی ہو، مختلف
LANGکے تحت مختلف output پیدا کر سکتی ہے۔ اگر بعد کا مرحلہ اس output کو parse کرتا ہے تو امید رکھنے کے بجائے اسکرپٹ میں locale مقرر کریں۔ - TTY (terminal) موجود نہیں ہوتا۔ کوئی command confirmation مانگنے، editor کھولنے یا progress bar دکھانے کی کوشش کرے تو وہ hang یا exit ہو سکتی ہے۔ tool کی فراہم کردہ non-interactive flag استعمال کریں۔
- SSH agent موجود نہیں ہوتا۔
SSH_AUTH_SOCKcron کے environment میں شامل نہیں ہوتا، اس لیےsshیاrsynccommand، جو اس لیے کامیاب ہوئی تھی کہ آپ کا agent loaded تھا، اب authenticate نہیں کر پاتی۔ job کے لیے الگ key دیں اور اسے job کے user کی ملکیت بنائیں۔ - user session bus موجود نہیں ہوتی، اس لیے cron job سے
systemctl --userfail ہو جاتی ہے جب تکXDG_RUNTIME_DIRمقرر نہ کیا جائے۔ system unit بہتر حل ہے۔
Fedora، Rocky اور Alma پر ایک اور ممکنہ وجہ بھی ہے۔ SELinux، cron jobs کو محدود کرتا ہے، اس لیے غیر متوقع label والے path تک رسائی کی کوشش مسترد ہو جاتی ہے، چاہے file permissions درست دکھائی دیں۔ sudo ausearch -m avc -ts recent سے denials کی جانچ کریں، اور کچھ بھی بند کرنے سے پہلے سرور کے لیے SELinux کی بنیادی باتیں پڑھیں۔
ایک منٹ کا probe جو cron کے environment کو دکھاتا ہے
اندازہ لگانا چھوڑ دیں کہ cron کے environment میں کیا موجود ہے، اور اسے براہ راست پڑھیں۔ ایک ایسی script لکھیں جو ہر چیز dump کرے، اسے ہر منٹ schedule کریں، انتظار کریں، پھر file پڑھیں۔
cat > /home/deploy/cron-probe.sh <<'EOF'
#!/bin/bash
echo "=== probe ==="
date -Is
pwd
id
echo "SHELL=$SHELL"
echo "LANG=$LANG"
command -v node || echo "node is not on this PATH"
env | sort
EOF
chmod +x /home/deploy/cron-probe.shجس user کے account سے اصل job چلتی ہے، اس کی crontab میں ایک line شامل کریں۔ دونوں طرف absolute paths استعمال کریں۔
* * * * * /home/deploy/cron-probe.sh >> /home/deploy/cron-probe.log 2>&1ایک منٹ انتظار کریں، پھر /home/deploy/cron-probe.log پڑھیں اور اس کا موازنہ اپنی shell میں چلائے گئے انہی commands سے کریں۔ PATH line، working directory اور locale عموماً failure کی وجہ خود واضح کر دیتے ہیں۔ اس setup کی 2 تفصیلات نوٹ کریں: percent signs script کے اندر موجود ہیں، جہاں cron کا rule لاگو نہیں ہوتا، اور log path ایسا ہے جس میں job کا user لکھ سکتا ہے۔
جواب ملتے ہی اس crontab line کو delete کر دیں۔ ہر منٹ چلنے والی اور file میں append کرنے والی job چھوٹی disk بھر دے گی، اور یہ کام خاموشی سے کرے گی۔
کیا schedule وہی ہے جو آپ کا مطلب تھا؟
صارف کی crontab لائن پانچ fields سے شروع ہوتی ہے: minute، hour، day of month، month، day of week۔ ان میں سے دو fields ایک دوسرے کے ساتھ ایسے interact کرتے ہیں کہ اکثر لوگ حیران ہو جاتے ہیں۔
جب day of month اور day of week دونوں restricted ہوں، یعنی دونوں میں سے کوئی بھی * نہ ہو، تو cron job اس وقت چلاتا ہے جب either field match کرے۔ 0 0 13 * 5 کا مطلب "Friday the 13th" نہیں ہے۔ یہ ہر ماہ کی 13 تاریخ کو midnight پر اور ہر Friday کو midnight پر چلتا ہے۔ صرف ایک مخصوص دن حاصل کرنے کے لیے دونوں میں سے ایک field کو * رہنے دیں اور دوسری field کو script کے اندر test کریں۔
cron system timezone استعمال کرتا ہے۔ بہت سی VPS images UTC (coordinated universal time) پر set ہوتی ہیں، اس لیے 03:00 کے لیے schedule کیا گیا job 03:00 UTC پر چلتا ہے، جو آپ کے مقامی وقت کے مطابق afternoon کے درمیان ہو سکتا ہے۔ timedatectl دکھاتا ہے کہ آپ کا box حقیقت میں کون سا timezone استعمال کر رہا ہے۔ یہ فرض کرنے کے بجائے کہ وہ آپ کے laptop کے timezone سے match کرتا ہے، اپنا timezone پڑھیں۔
schedule کے دو مزید traps بھی جاننے چاہییں۔ @reboot اس وقت fire ہوتا ہے جب خود cron start ہوتا ہے۔ یہ network کے ready ہونے کا وہی لمحہ نہیں ہوتا، اس لیے DNS یا remote host درکار job boot کے وقت fail ہو سکتا ہے اور اس کے بعد ہر manual run پر کامیاب ہو سکتا ہے۔ اسی طرح slow job کو اس وقت دوبارہ start ہونے سے روکنے والی کوئی چیز نہیں ہوتی جب پچھلی copy ابھی چل رہی ہو۔ اسے lock کے اندر wrap کریں۔
*/5 * * * * /usr/bin/flock -n /tmp/backup-site.lock /usr/local/sbin/backup-site.sh >> /var/log/backup-site.log 2>&1flock -n lock پہلے سے held ہونے کی صورت میں فوراً give up کرتا ہے، اس لیے overlapping run رک جاتا ہے اور پہلی run کے اوپر جمع نہیں ہوتا۔
جب systemd timer بہتر انتخاب ہو
cron ایک کام کے لیے اچھا ہے: کسی مقررہ وقت پر ایک command چلانا۔ اس کے علاوہ اس کی صلاحیتیں محدود ہیں۔ timer، کسی redirect کے بغیر journal، بعد میں معلوم کیا جا سکنے والا exit status، network-online.target کے ساتھ ordering، اور randomized delay فراہم کرتا ہے، تاکہ سو servers ایک ہی second میں شروع نہ ہوں۔ جب job کو ان میں سے کسی سہولت کی ضرورت ہو تو VPS پر systemd service اور timer بنانا crontab line کا دفاع کرنے سے کم محنت طلب ہے۔ Retry behaviour بھی وہیں رکھیں، کیونکہ systemd restart policies یہ طے کرتی ہیں کہ failure کے بعد کیا ہوگا، جبکہ cron کے پاس اس سوال کا کوئی جواب نہیں۔
چھوٹی jobs کے لیے cron برقرار رکھیں۔ Dependencies یا retry policy رکھنے والی ہر چیز کو timer پر منتقل کریں۔ دونوں ایک ہی server پر چل سکتے ہیں، اس لیے یہ migration ایک ہی نشست میں مکمل کرنا ضروری نہیں۔
FAQ
میرا cron job ہاتھ سے چلتا ہے لیکن cron سے ناکام کیوں ہوتا ہے؟
کیونکہ آپ کے shell اور cron کا environment مختلف ہوتا ہے۔ آپ کا login shell /etc/profile اور ~/.bashrc پڑھتا ہے، جو PATH، locale اور agent variables متعین کرتے ہیں۔ cron ان میں سے کچھ بھی شامل کیے بغیر، مختلف working directory سے، اور بعض اوقات مختلف shell کے ذریعے command شروع کرتا ہے۔ ہر command کے لیے absolute paths استعمال کریں، crontab کے شروع میں یا script کے اندر مطلوبہ values متعین کریں، اور ایک منٹ بعد چلنے والا probe job schedule کریں جو env | sort، pwd اور id کو log file میں لکھے۔ اس طرح اندازہ لگانے کے بجائے cron کا اصل environment پڑھ سکیں گے۔
میں کیسے جانچوں کہ cron نے واقعی میرا job چلایا تھا؟
daemon کا log پڑھیں۔ Debian اور Ubuntu پر journalctl -u cron، یا Fedora، Rocky اور Alma پر journalctl -u crond استعمال کریں۔ بعض images میں messages rsyslog کے ذریعے /var/log کے تحت کسی file میں بھیجے جاتے ہیں۔ اس minute پر entry تلاش کریں جس کا schedule میں ذکر ہے، اور تصدیق کریں کہ اس میں آپ کی command کا نام موجود ہے۔ اگر entry نہ ہو تو cron کو schedule ملا ہی نہیں تھا، اس لیے تصدیق کریں کہ آپ نے درست crontab میں ترمیم کی ہے۔ اگر entry موجود ہو لیکن نتیجہ نہ ہو تو command شروع ہو کر بند ہو گئی؛ اس کا output redirect کے ذریعے محفوظ کریں۔
crontab کے اندر date +%Y کیوں ناکام ہوتا ہے؟
cron command field میں % کو special character سمجھتا ہے۔ پہلا unescaped % command ختم کر دیتا ہے، اس کے بعد موجود تمام متن اسی command کو standard input کے طور پر دیا جاتا ہے، اور ہر مزید % newline بن جاتا ہے۔ اس لیے date-formatted filename اس program تک نہیں پہنچتا جس کے لیے آپ نے اسے لکھا تھا۔ ہر percent کو \% کے طور پر escape کریں، یا command کو script میں منتقل کر کے script کو cron سے چلائیں؛ script کے اندر percent sign کا کوئی special meaning نہیں ہوتا۔
میرے cron job کا output کہاں جاتا ہے؟
یہ local mail system کو بھیجا جاتا ہے، اور crontab کے owner یا MAILTO کے بتائے گئے پتے کو address کیا جاتا ہے۔ زیادہ تر VPS images میں mail transfer agent نصب نہیں ہوتا، اس لیے message discard ہو جاتا ہے اور job خاموش محسوس ہوتا ہے۔ output کو >> /path/to/log 2>&1 کے ذریعے file میں redirect کریں۔ ترتیب برقرار رکھیں تاکہ standard error، standard output کے بعد اسی جگہ جائے۔ متبادل طور پر اسے logger -t myjob کے ذریعے pipe کریں اور journalctl -t myjob سے واپس پڑھیں۔ debugging مکمل ہونے تک > /dev/null 2>&1 استعمال نہ کریں۔
کیا مجھے cron استعمال کرنا چاہیے یا systemd timer؟
مقررہ وقت پر سادہ command چلانے کے لیے cron استعمال کریں، خاص طور پر جب اسے ایسی machine پر منتقل کرنا ہو جو systemd نہیں چلاتی۔ جب redirect کے بغیر output journal میں چاہیے، exit status کو query کرنا ہو، network کے up ہونے کے بعد ordering درکار ہو، randomized start delay چاہیے، یا failure کے بعد retry policy درکار ہو تو timer استعمال کریں۔ دونوں ایک ہی server پر چل سکتے ہیں، اس لیے jobs کو ضرورت کے مطابق ایک ایک کر کے منتقل کیا جا سکتا ہے۔