کرون جاب هاست: زمان‌بندی درست و رفع خطاها

کرون جاب هاست را درست تنظیم کنید: مسیر مطلق PHP، نحو زمان‌بندی، گرفتن خروجی برای عیب‌یابی و اشتباه‌هایی که باعث اجرا نشدن می‌شوند.

۶ دقیقه به‌روزرسانی ۴ مهر ۱۴۰۵

کرون جاب را ذخیره کرده‌اید، منتظر مانده‌اید، و هیچ اتفاقی نیفتاده. نه ایمیلی آمده، نه فایلی ساخته شده، نه رکوردی در دیتابیس اضافه شده. این دقیقاً همان لحظه‌ای است که باید بفهمید کرون جاب هاست چطور اجرا می‌شود و چرا سکوت می‌کند. مشکل تقریباً همیشه یکی از سه چیز است: مسیر اشتباه، نحو غلط زمان‌بندی، یا خروجی‌ای که جایی نمی‌رود و شما نمی‌بینیدش.

مسیر مطلق PHP؛ جایی که بیشتر کرون جاب‌ها می‌میرند

در کنترل‌پنل، فیلد Command را با php /home/user/public_html/cron.php پر می‌کنید و فکر می‌کنید کار تمام است. نیست. کرون در محیطی اجرا می‌شود که PATH آن با شل تعاملی شما فرق دارد. ممکن است php اصلاً پیدا نشود، یا نسخه‌ای پیدا شود که با نسخه‌ای که سایت روی آن اجرا می‌شود یکی نیست.

اول مسیر واقعی باینری را پیدا کنید:

which php
# /usr/local/bin/php
php -v
# PHP 8.2.18 (cli)

بعد همان مسیر مطلق را در Command بنویسید:

/usr/local/bin/php /home/username/public_html/cron.php

اگر سایت روی PHP 8.2 اجرا می‌شود و CLI روی 7.4 است، اسکریپت شما ممکن است با خطای parse بمیرد و شما هیچ‌وقت آن خطا را نبینید. این تفاوت نسخه، یکی از رایج‌ترین دلایل «کار می‌کند ولی نتیجه نمی‌دهد» است.

چرا مسیر نسبی کار نمی‌کند

کرون با پوشه کاری $HOME اجرا می‌شود، نه با پوشه اسکریپت. اگر داخل کد از require 'config.php' استفاده کرده‌اید، فایل پیدا نمی‌شود. همیشه مسیر مطلق بدهید یا اول chdir(__DIR__) بزنید.

نحو زمان‌بندی: پنج ستاره که همه اشتباه می‌خوانند

قالب استاندارد پنج فیلد دارد: دقیقه، ساعت، روز ماه، ماه، روز هفته. ترتیب را حفظ کنید و برای «هر پنج دقیقه» بنویسید */5 * * * *. برای «هر شب ساعت ۳ بامداد» بنویسید 0 3 * * *.

عبارتمعنیکاربرد رایج
*/5 * * * *هر ۵ دقیقههمگام‌سازی سبک
0 * * * *ابتدای هر ساعتپاکسازی کش
0 3 * * *هر روز ۳ بامدادبکاپ دیتابیس
0 0 1 * *اول هر ماهگزارش ماهانه
0 4 * * 0یکشنبه‌ها ۴ بامدادبه‌روزرسانی هفتگی

نکته‌ای که کمتر گفته می‌شود: فیلد روز ماه و روز هفته با هم OR می‌شوند، نه AND. اگر بنویسید 0 0 1 * 0، اسکریپت هم اول ماه و هم هر یکشنبه اجرا می‌شود. اگر می‌خواهید فقط اول ماهِ یکشنبه‌ها اجرا شود، باید شرط را داخل کد چک کنید.

این‌جا اشتباه می‌کنند

بیشترین اشتباهی که دیده‌ام این است: کاربر زمان‌بندی را روی * * * * * می‌گذارد تا «سریع تست کند»، بعد فراموش می‌کند عوضش کند. علامتش هم واضح است؛ لاگ سرور پر می‌شود از ورودی‌های تکراری، مصرف منابع هاست بالا می‌رود و سایت کند می‌شود. اگر محدودیت‌های منابع را نمی‌شناسید، پیش از هر تستی مرجع کامل محدودیت‌های منابع هاست را بخوانید تا بفهمید هر عدد چه چیزی را می‌شمارد.

خروجی را بگیرید، وگرنه کور می‌مانید

کرون به‌طور پیش‌فرض خروجی را برای شما ایمیل می‌کند، ولی این ایمیل اغلب به اسپم می‌رود یا اصلاً ارسال نمی‌شود. راه مطمئن‌تر، هدایت خروجی به فایل است:

/usr/local/bin/php /home/username/public_html/cron.php >> /home/username/cron.log 2>&1

حالا 2>&1 باعث می‌شود خطاهای stderr هم در همان فایل بنشینند. اگر فایل خالی ماند، یعنی اسکریپت اجرا شده و خطایی نداده. اگر فایل اصلاً ساخته نشد، یعنی کرون به آن خط نرسیده و مشکل در مسیر یا زمان‌بندی است.

برای اسکریپت‌های طولانی، قفل فایل هم بگذارید تا اجرای هم‌زمان رخ ندهد:

*/10 * * * * /usr/bin/flock -n /tmp/mycron.lock /usr/local/bin/php /home/username/public_html/cron.php >> /home/username/cron.log 2>&1

بدون این قفل، اگر اجرای قبلی هنوز تمام نشده باشد، نسخه بعدی روی همان دیتابیس می‌افتد و رکوردهای تکراری می‌سازد. این را در همگام‌سازی‌های API زیاد دیده‌ام.

کرون جاب هاست اشتراکی در برابر سرور اختصاصی

روی هاست اشتراکی، کرون در محیط محدودی اجرا می‌شود. تعداد اجرای هم‌زمان محدود است و اسکریپت‌های سنگین ممکن است وسط کار قطع شوند. اگر کار شما پردازش تصویر، ایمپورت سنگین یا اسکن هزاران رکورد است، این محیط جای مناسبی نیست.

اینجا انتخاب واقعی وجود دارد. برای کارهای سبک و دوره‌ای، همان هاست اشتراکی کافی است و مدیریتش ساده‌تر. برای پردازش‌های سنگین یا اجرای هر دقیقه، به سرور اختصاصی یا VPS مهاجرت کنید؛ آنجا هم کنترل کامل دارید و هم می‌توانید systemd timer به‌جای cron بگذارید که لاگ‌گیری و مدیریت خطای بهتری دارد. من برای هر چیزی زیر یک دقیقه اجرا، systemd را ترجیح می‌دهم.

محدودیت اجرای هم‌زمان را جدی بگیرید

اگر چند کرون جاب سنگین را روی هم بگذارید، ممکن است به سقف Entry Process بخورید و سایت برای بازدیدکننده‌ها کند یا بی‌پاسخ شود. تفاوت این مفهوم با بازدید عادی را در توضیح Entry Process و تفاوتش با بازدید آورده‌ایم. راه‌حل ساده: زمان‌بندی‌ها را پخش کنید. یکی ساعت ۲، یکی ۳، یکی ۴.

چک‌لیست عیب‌یابی وقتی کرون اجرا نمی‌شود

  1. مسیر مطلق باینری PHP را با which php تأیید کنید.
  2. مسیر مطلق فایل اسکریپت را کامل بنویسید.
  3. خروجی را به فایل هدایت کنید و بعد از یک چرخه، فایل را بخوانید.
  4. اسکریپت را دستی از SSH اجرا کنید: /usr/local/bin/php /home/username/public_html/cron.php. اگر دستی هم کار نکرد، مشکل کرون نیست، مشکل کد است.
  5. مجوز فایل را چک کنید؛ فایل باید برای کاربر هاست قابل خواندن باشد.
  6. اگر اسکریپت به دیتابیس وصل می‌شود، از localhost استفاده کنید نه IP عمومی.

مرحله چهارم را جدی بگیرید. نیمی از تیکت‌هایی که به دست ما می‌رسد، بعد از اجرای دستی مشخص می‌شود که اسکریپت از ابتدا خطای کد داشته و کرون بی‌تقصیر بوده. اگر خطای PHP می‌گیرید، راهنمای رفع صفحه سفید و خطایابی PHP نقطه شروع خوبی است.

کرون برای وردپرس و کارهای رایج

وردپرس خودش سیستم زمان‌بندی داخلی دارد (WP-Cron) که با بازدید کاربر trigger می‌شود. اگر ترافیک سایت کم است، این سیستم دیر اجرا می‌شود. راه‌حل استاندارد، غیرفعال کردن WP-Cron و صدا زدن آن با کرون واقعی است:

# در wp-config.php
define('DISABLE_WP_CRON', true);

# در کرون جاب
*/15 * * * * /usr/local/bin/php /home/username/public_html/wp-cron.php >> /home/username/cron.log 2>&1

برای بکاپ دیتابیس هم مستقیم mysqldump نزنید؛ اول خروجی را به فایل موقت بدهید و بعد فشرده کنید، وگرنه با دیتابیس‌های بزرگ به سقف حافظه می‌خورید.

اگر تازه سایت را بالا آورده‌اید و هنوز با ساختار پوشه‌ها راحت نیستید، راهنمای آپلود سایت روی هاست مسیرها را روشن می‌کند. برای تست‌های شبکه و DNS هم ابزارهای رایگان وب‌مستر کار را سریع‌تر می‌کند.

اگر روی هاست لینوکس کار می‌کنید، بخش Cron Jobs در کنترل‌پنل همان جایی است که این خطوط را وارد می‌کنید؛ فقط یادتان باشد بعد از هر تغییر، یک بار خروجی را چک کنید.

پرسش‌های پرتکرار

چرا کرون جاب اجرا می‌شود ولی هیچ نتیجه‌ای نمی‌بینم؟

تقریباً همیشه به این برمی‌گردد که اسکریپت اجرا می‌شود اما خطا می‌دهد و خطا جایی ثبت نمی‌شود. خروجی را با >> /home/username/cron.log 2>&1 به فایل هدایت کنید و بعد از یک چرخه کامل، فایل را بخوانید. اگر فایل خالی بود، اسکریپت بدون خطا اجرا شده و مشکل در منطق کد یا اتصال دیتابیس است.

مسیر PHP در کرون جاب را از کجا بفهمم؟

با دستور which php در SSH. خروجی معمولاً چیزی مثل /usr/local/bin/php است. همان مسیر مطلق را در فیلد Command بنویسید. اگر نسخه CLI با نسخه‌ای که سایت روی آن اجرا می‌شود فرق دارد، با php -v چک کنید و در صورت نیاز مسیر نسخه درست را بدهید.

آیا می‌توانم کرون جاب را هر دقیقه اجرا کنم؟

فنی‌اش بله، ولی روی هاست اشتراکی توصیه نمی‌کنم. اجرای هر دقیقه‌ای منابع را می‌خورد و اگر اسکریپت سنگین باشد، به سقف Entry Process می‌خورید و سایت کند می‌شود. برای کارهای واقعاً زمان‌حساس، سرور اختصاصی یا VPS انتخاب درست‌تری است.

تفاوت WP-Cron با کرون جاب سرور چیست؟

WP-Cron با هر بازدید کاربر trigger می‌شود، پس روی سایت‌های کم‌ترافیک دیر یا اصلاً اجرا نمی‌شود. کرون جاب سرور مستقل از بازدید و طبق زمان‌بندی شما اجرا می‌شود. برای سایت‌های جدی، WP-Cron را غیرفعال کنید و آن را با کرون واقعی صدا بزنید.

یک کار را همین حالا انجام دهید: خروجی کرون را به فایل هدایت کنید و یک چرخه صبر کنید. تا وقتی آن فایل را نبینید، هر تغییر دیگری حدس و گمان است.

آیا این مطلب برایتان مفید بود؟