سی ام اس نویسسی ام اس نویسیاد بگیر، سیستم خودتو بنویس
مجلهتماس با ما
سی ام اس نویسسی ام اس نویس

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

پیوندهای سریع
محصولات فیزیکیمحصولات دیجیتالدوره‌های آموزشی
سی ام اس نویس
مجله سی ام اس نویستماس با ماپنل کاربری
سی ام اس نویس — تمامی حقوق برای سی ام اس نویس محفوظ است. © 1406 تماس با ما09307711941
Task Scheduling در Laravel چیست؟ آموزش کامل زمان‌بندی وظایف در لاراول

Task Scheduling در Laravel چیست؟ آموزش کامل زمان‌بندی وظایف در لاراول

ممدیر کل سیستم ۱۵ مهر ۱۴۰۵ ۲۱ دقیقه مطالعه ۱ بازدید
Task Scheduling در Laravel چیست؟ آموزش کامل زمان‌بندی وظایف در لاراول

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

برای مثال ممکن است بخواهیم:

  • هر روز گزارش فروش ایجاد شود.
  • هر ساعت اطلاعاتی از یک API دریافت شود.
  • هر شب داده‌های قدیمی پاک شوند.
  • هر دقیقه وضعیت یک سرویس بررسی شود.
  • هر هفته یک گزارش برای مدیر ارسال شود.
  • Subscriptionهای منقضی‌شده بررسی شوند.
  • Cacheهای خاصی بازسازی شوند.
  • Jobهای مشخصی در زمان معین اجرا شوند.

برای انجام این کارها در Laravel می‌توان از Task Scheduling استفاده کرد.

Task Scheduling یا Scheduler لاراول به ما اجازه می‌دهد اجرای Commandها، Jobها، Closureها و بعضی عملیات دیگر را طبق یک برنامه زمانی مشخص مدیریت کنیم.

در این مقاله از مفهوم Scheduler شروع می‌کنیم و سپس نحوه تعریف Schedule، اتصال آن به Cron، اجرای schedule:run و schedule:work، زمان‌بندی Command و Job و نکات مهم Production را بررسی می‌کنیم.


# Task Scheduling در Laravel چیست؟

Task Scheduling سیستمی در Laravel برای زمان‌بندی اجرای خودکار وظایف است.

به جای اینکه برای هر عملیات یک Cron Job جداگانه در سرور ایجاد کنیم، می‌توانیم زمان‌بندی وظایف را داخل خود پروژه Laravel تعریف کنیم.

برای مثال:


Schedule::command('reports:daily')->daily();

این کد به Laravel می‌گوید:

> Command مربوط به reports:daily را روزانه اجرا کن.

یا:


Schedule::call(function () {

    // عملیات موردنظر

})->hourly();

یعنی Closure موردنظر را هر ساعت اجرا کن.

در نتیجه Laravel تبدیل به مرکزی برای مدیریت Taskهای زمان‌بندی‌شده پروژه می‌شود.


# چرا از Laravel Scheduler استفاده کنیم؟

بدون Scheduler ممکن است مجبور شویم تعداد زیادی Cron Job روی سرور تعریف کنیم.

مثلاً:


Cron 1 → پاک کردن سفارش‌های موقت

Cron 2 → ارسال گزارش

Cron 3 → بررسی Subscription

Cron 4 → دریافت نرخ ارز

Cron 5 → پاک کردن فایل‌های قدیمی

اما با Laravel Scheduler می‌توانیم همه این زمان‌بندی‌ها را در Application مدیریت کنیم:


                Laravel Scheduler

                       │

       ┌───────────────┼───────────────┐

       ↓               ↓               ↓

   Command           Job            Closure

       ↓               ↓               ↓

   Daily             Hourly          Weekly

این روش باعث می‌شود منطق زمان‌بندی داخل خود پروژه قرار بگیرد و مدیریت آن ساده‌تر شود.


# تفاوت Scheduler با Cron چیست؟

این دو مفهوم یکی نیستند.

Cron

Cron یک سیستم زمان‌بندی در سطح سیستم‌عامل است.

مثلاً روی Linux می‌توان یک Cron Job تعریف کرد:


* * * * * cd /var/www/example && php artisan schedule:run >> /dev/null 2>&1

Laravel Scheduler

Scheduler سیستم زمان‌بندی داخلی Laravel است.

مثلاً:


Schedule::command('reports:daily')->daily();

در این معماری:


Linux Cron

     ↓

schedule:run

     ↓

Laravel Scheduler

     ↓

بررسی Taskها

     ↓

اجرای Taskهای موعددار

بنابراین Cron و Laravel Scheduler رقیب یکدیگر نیستند.

Cron معمولاً مسئول بیدار کردن Scheduler است و Laravel مسئول مدیریت زمان‌بندی Taskهای Application است.


# Laravel Scheduler در کجا قرار دارد؟

در نسخه‌های جدید Laravel، تعریف Schedule معمولاً در:


routes/console.php

انجام می‌شود.

برای مثال:


use Illuminate\Support\Facades\Schedule;



Schedule::call(function () {

    // عملیات

})->daily();

این موضوع با ساختار نسخه‌های قدیمی Laravel متفاوت است؛ بنابراین اگر آموزش‌های قدیمی اینترنت را می‌خوانید، ممکن است محل تعریف Scheduler متفاوت باشد.

در پروژه‌های جدید بهتر است ساختار فعلی پروژه خود را مبنا قرار دهید.


# اولین Task زمان‌بندی‌شده در Laravel

فرض کنیم می‌خواهیم یک عملیات را هر روز اجرا کنیم.

در routes/console.php:


use Illuminate\Support\Facades\Schedule;



Schedule::call(function () {

    \Log::info('Daily task executed.');

})->daily();

اکنون Laravel این Task را به‌عنوان یک عملیات روزانه می‌شناسد.

اما هنوز یک نکته مهم وجود دارد:

Laravel خودش بدون Scheduler Trigger خارجی، زمان‌بندی را اجرا نمی‌کند.

برای اجرای Scheduler باید آن را از طریق Cron یا فرآیند مناسب دیگری اجرا کنیم.


# schedule:run چیست؟

یکی از مهم‌ترین دستورات Scheduler این دستور است:


php artisan schedule:run

این دستور Scheduleهای Laravel را بررسی می‌کند و Taskهایی را که زمان اجرای آنها رسیده است، اجرا می‌کند.

مثلاً:


php artisan schedule:run

Laravel بررسی می‌کند:


Task A → موعدش رسیده؟

Task B → موعدش رسیده؟

Task C → موعدش رسیده؟

Task D → هنوز زود است؟

و فقط Taskهای لازم را اجرا می‌کند.


# Cron برای Laravel Scheduler

در Production معمولاً یک Cron Job برای اجرای Scheduler تعریف می‌شود.

نمونه:


* * * * * cd /var/www/example && php artisan schedule:run >> /dev/null 2>&1

در اینجا:


* * * * *

یعنی Cron هر دقیقه اجرا شود.

سپس:


php artisan schedule:run

Scheduler Laravel را اجرا می‌کند.

در نتیجه:


هر دقیقه

   ↓

Cron

   ↓

schedule:run

   ↓

Laravel

   ↓

بررسی Scheduleها

   ↓

اجرای Taskهای موعددار

این یکی از مهم‌ترین بخش‌های راه‌اندازی Scheduler در Production است.


# چگونه Cron را برای Laravel تنظیم کنیم؟

روی Ubuntu یا سایر Linuxهای دارای Cron می‌توانید Cron را با دستور زیر باز کنید:


crontab -e

سپس این خط را اضافه کنید:


* * * * * cd /var/www/example && php artisan schedule:run >> /dev/null 2>&1

البته مسیر:


/var/www/example

باید با مسیر واقعی پروژه Laravel شما جایگزین شود.

مثلاً اگر پروژه در:


/home/example.com/public_html

باشد:


* * * * * cd /home/example.com/public_html && php artisan schedule:run >> /dev/null 2>&1


# چرا Cron را هر دقیقه اجرا می‌کنیم؟

ممکن است بپرسید اگر Task ما روزانه است، چرا Cron را هر دقیقه اجرا کنیم؟

چون Cron وظیفه ندارد مستقیماً Task روزانه را اجرا کند.

وظیفه آن این است که Scheduler Laravel را مرتب بررسی کند.

مثلاً:


Schedule::command('reports:daily')->dailyAt('02:00');

Cron هر دقیقه Laravel را اجرا می‌کند و Laravel بررسی می‌کند که آیا ساعت به 02:00 رسیده است یا خیر.

اگر نرسیده باشد:


Nothing to run

و اگر رسیده باشد:


Run reports:daily


# schedule:work چیست؟

Laravel علاوه بر schedule:run، دستور دیگری نیز برای اجرای Scheduler دارد:


php artisan schedule:work

این دستور Scheduler را به‌صورت مداوم در حال اجرا نگه می‌دارد و برای محیط‌هایی که می‌خواهید Scheduler به‌صورت دائمی در حال کار باشد، کاربرد دارد.

در محیط Development می‌توانید برای تست Scheduler از آن استفاده کنید:


php artisan schedule:work

سپس Terminal را باز نگه دارید و منتظر اجرای Task باشید.

این روش برای تست زمان‌بندی بسیار راحت است.


# schedule:run یا schedule:work؟

به‌صورت ساده:

دستورکاربرد
schedule:runاجرای یک‌باره بررسی Scheduler
schedule:workاجرای مداوم Scheduler

در Production معمولاً می‌توانید Scheduler را با Cron و schedule:run مدیریت کنید.

در برخی معماری‌ها نیز اجرای دائمی schedule:work می‌تواند گزینه مناسبی باشد.

انتخاب روش باید با معماری Deployment پروژه شما هماهنگ باشد.


# زمان‌بندی Command در Laravel

یکی از بهترین کاربردهای Scheduler، اجرای Artisan Command است.

فرض کنید Command زیر را ساخته‌ایم:


php artisan make:command GenerateDailyReport

بعد از پیاده‌سازی Command می‌توانیم آن را زمان‌بندی کنیم:


Schedule::command('report:generate')->daily();

یا مثلاً:


Schedule::command('report:generate')->hourly();

در این حالت Laravel اجرای Command را مدیریت می‌کند.


# زمان‌بندی Job در Laravel

Scheduler فقط مخصوص Command نیست.

می‌توان Jobها را نیز زمان‌بندی کرد.

مثلاً:


Schedule::job(new GenerateReport)->daily();

در این حالت Laravel Job را طبق Schedule موردنظر Dispatch می‌کند.

اگر Queue نیز تنظیم شده باشد، Job می‌تواند برای پردازش پس‌زمینه وارد Queue شود.

معماری می‌تواند به شکل زیر باشد:


Scheduler

    ↓

Dispatch Job

    ↓

Queue

    ↓

Worker

    ↓

Process

این ترکیب در پروژه‌های بزرگ Laravel بسیار کاربردی است.


# ترکیب Scheduler و Queue

فرض کنید هر شب باید گزارش فروش تولید شود.

اگر تولید گزارش سنگین باشد، بهتر است Scheduler مستقیماً عملیات سنگین را انجام ندهد.

بهتر است:


Scheduler

    ↓

Dispatch Job

    ↓

Redis / Queue

    ↓

Worker

    ↓

Generate Report

مثلاً:


Schedule::job(new GenerateDailySalesReport)->dailyAt('01:00');

در این معماری Scheduler فقط Job را وارد Queue می‌کند و Worker عملیات سنگین را انجام می‌دهد.

این روش برای پروژه‌های بزرگ بسیار مناسب‌تر است.


# زمان‌بندی Closure

می‌توان یک Closure را نیز زمان‌بندی کرد:


Schedule::call(function () {

    // عملیات موردنظر

})->daily();

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

اما اگر عملیات پیچیده شود، معمولاً بهتر است منطق را به:

  • Command
  • Job
  • Service

منتقل کنیم.


# زمان‌بندی در هر دقیقه

برای اجرای Task در هر دقیقه:


Schedule::call(function () {

    // Task

})->everyMinute();

این یکی از ساده‌ترین Intervalها در Scheduler است.


# اجرای Task هر پنج دقیقه


Schedule::call(function () {

    // Task

})->everyFiveMinutes();

مثلاً می‌توان برای بررسی وضعیت سرویس‌ها استفاده کرد.


# اجرای Task هر ده دقیقه


Schedule::call(function () {

    // Task

})->everyTenMinutes();


# اجرای Task هر پانزده دقیقه


Schedule::call(function () {

    // Task

})->everyFifteenMinutes();


# اجرای Task هر سی دقیقه


Schedule::call(function () {

    // Task

})->everyThirtyMinutes();


# اجرای Task هر ساعت


Schedule::call(function () {

    // Task

})->hourly();


# اجرای Task روزانه


Schedule::call(function () {

    // Task

})->daily();

این Task به‌صورت روزانه اجرا می‌شود.


# اجرای Task در ساعت مشخص

اگر بخواهیم Task هر روز در ساعت مشخصی اجرا شود:


Schedule::call(function () {

    // Generate report

})->dailyAt('02:00');

یعنی:


هر روز ساعت 02:00


# اجرای Task هفتگی

برای اجرای هفتگی:


Schedule::call(function () {

    // Weekly task

})->weekly();


# اجرای Task ماهانه

برای اجرای ماهانه:


Schedule::call(function () {

    // Monthly task

})->monthly();


# اجرای Task در روز خاص

می‌توان زمان‌بندی را دقیق‌تر کرد.

مثلاً:


Schedule::call(function () {

    // Weekly report

})->weeklyOn(1, '08:00');

در اینجا می‌توان روز و ساعت اجرای Task را مشخص کرد.


# زمان‌بندی با Cron Expression

Laravel امکان استفاده از Cron Expression را نیز فراهم می‌کند.

مثلاً:


Schedule::command('report:generate')

    ->cron('0 2 * * *');

این Expression یعنی Task در ساعت 2 بامداد اجرا شود.

Cron Expression برای زمان‌بندی‌های پیچیده‌تر بسیار قدرتمند است.

اما برای زمان‌بندی‌های معمول، متدهای خواناتر Laravel معمولاً انتخاب بهتری هستند:


->dailyAt('02:00')

به‌جای:


->cron('0 2 * * *')


# timezone در Laravel Scheduler

زمان‌بندی‌ها باید با Timezone موردنظر Application هماهنگ باشند.

فرض کنید:


Schedule::command('report:generate')

    ->dailyAt('02:00');

اگر Timezone پروژه با Timezone موردنظر شما متفاوت باشد، Task ممکن است در ساعت اشتباه اجرا شود.

بنابراین در پروژه‌های بین‌المللی باید Timezone را جدی بگیرید.

این موضوع مخصوصاً برای سیستم‌هایی که کاربران آنها در کشورهای مختلف هستند اهمیت زیادی دارد.


# جلوگیری از اجرای همزمان Task

گاهی ممکن است یک Task هنوز تمام نشده باشد ولی زمان اجرای بعدی آن فرا برسد.

مثلاً Task هر دقیقه اجرا می‌شود:


Schedule::command('sync:services')->everyMinute();

اما اجرای آن 3 دقیقه طول می‌کشد.

ممکن است در شرایط نامناسب چند نسخه همزمان اجرا شوند.

برای چنین سناریوهایی می‌توان از قابلیت جلوگیری از اجرای همزمان استفاده کرد:


Schedule::command('sync:services')

    ->everyMinute()

    ->withoutOverlapping();

در این حالت Laravel تلاش می‌کند تا زمانی که اجرای قبلی تمام نشده، اجرای بعدی را شروع نکند.

این قابلیت برای Taskهای طولانی بسیار مهم است.


# بدون Overlap چه مشکلی ایجاد می‌شود؟

فرض کنید:


00:00 → Task Start

00:01 → Task Start

00:02 → Task Start

00:03 → Task Start

اگر Task سه دقیقه طول بکشد، ممکن است چند نسخه همزمان فعال شوند.

برای عملیاتی مانند:

  • Synchronization
  • Import
  • پردازش سفارش
  • تولید گزارش
  • دریافت اطلاعات API

این وضعیت می‌تواند مشکل‌ساز شود.

با:


->withoutOverlapping()

می‌توان این ریسک را کاهش داد.


# اجرای Task فقط روی یک سرور

اگر Application شما روی چند Server اجرا شود:


Server 1

Server 2

Server 3

و Scheduler روی هر سه Server اجرا شود، ممکن است یک Task سه بار اجرا شود.

در چنین شرایطی می‌توان از قابلیت اجرای Task روی یک Server استفاده کرد:


Schedule::command('report:generate')

    ->daily()

    ->onOneServer();

این قابلیت برای معماری‌های Multi-Server اهمیت زیادی دارد.

البته استفاده صحیح از آن نیازمند تنظیم Cache Store مشترک بین Serverها است.


# اجرای Task فقط در محیط Production

گاهی یک Task نباید در محیط Development اجرا شود.

می‌توان اجرای آن را به Environment مشخص محدود کرد:


Schedule::command('report:generate')

    ->daily()

    ->environments(['production']);

در نتیجه این Task فقط در Environment موردنظر اجرا خواهد شد.

این قابلیت برای جلوگیری از اجرای اشتباه Taskهای حساس در محیط Development بسیار مفید است.


# شرط‌گذاری روی Taskها

گاهی نمی‌خواهیم Task همیشه اجرا شود.

مثلاً فقط زمانی اجرا شود که شرایط خاصی برقرار باشد.

می‌توان از شرط استفاده کرد:


Schedule::command('report:generate')

    ->daily()

    ->when(function () {

        return true;

    });

همچنین می‌توان شرایطی برای جلوگیری از اجرا تعریف کرد.

این قابلیت برای Scheduleهای پیچیده‌تر کاربرد دارد.


# اجرای Task در شرایط خاص

فرض کنید یک سرویس فقط زمانی باید Billing شود که استفاده‌ای در آن روز ثبت شده باشد.

می‌توان منطق شرط را در Scheduler یا Command مربوطه قرار داد.

برای مثال:


Schedule::command('billing:process')

    ->daily()

    ->when(fn () => /* condition */);

اما برای منطق تجاری پیچیده بهتر است Condition اصلی داخل Service یا Command قرار گیرد و Scheduler فقط مسئول زمان‌بندی باشد.


# مدیریت خروجی Command

گاهی می‌خواهیم خروجی Command زمان‌بندی‌شده در فایل ذخیره شود.

برای مثال:


Schedule::command('report:generate')

    ->daily()

    ->appendOutputTo(storage_path('logs/report.log'));

این قابلیت برای Debug و بررسی اجرای Taskها می‌تواند مفید باشد.


# ثبت خروجی و Debug کردن Scheduler

یکی از مشکلات رایج این است که Task اجرا نمی‌شود و مشخص نیست مشکل کجاست.

برای Debug ابتدا می‌توان Command را دستی اجرا کرد:


php artisan report:generate

اگر Command دستی اجرا نشود، مشکل احتمالاً مربوط به خود Command است، نه Scheduler.

بعد Scheduler را بررسی کنید:


php artisan schedule:run

و در صورت نیاز Logهای Laravel را بررسی کنید.


# لیست Taskهای زمان‌بندی‌شده

برای بررسی Scheduleهای تعریف‌شده می‌توان از Artisan استفاده کرد:


php artisan schedule:list

این دستور برای Debug کردن Scheduler بسیار مفید است.

با استفاده از آن می‌توانید ببینید چه Taskهایی تعریف شده‌اند و زمان‌بندی آنها چیست.


# Task Scheduling و Cron در Production

یک معماری معمول Production به شکل زیر است:


Linux Cron

     │

     │ Every Minute

     ↓

php artisan schedule:run

     ↓

Laravel Scheduler

     │

     ├── Daily Command

     ├── Hourly Job

     ├── Every 5 Minutes

     └── Weekly Report

این ساختار ساده، قابل مدیریت و بسیار رایج است.


# Task Scheduling و Queue چه تفاوتی دارند؟

این دو مفهوم را نباید با هم اشتباه گرفت.

Scheduler

مشخص می‌کند:

> چه زمانی یک Task اجرا شود؟

Queue

مشخص می‌کند:

> یک Job چگونه در پس‌زمینه پردازش شود؟

مثلاً:


Scheduler

   ↓

هر روز ساعت 01:00

   ↓

Dispatch Job

   ↓

Queue

   ↓

Worker

   ↓

Execute

در این معماری هر کدام وظیفه مشخصی دارند.


# Scheduler جایگزین Queue نیست

فرض کنید یک گزارش بسیار سنگین داریم.

اشتباه:


Scheduler

   ↓

Generate huge report

بهتر:


Scheduler

   ↓

Dispatch Job

   ↓

Queue

   ↓

Worker

   ↓

Generate report

Scheduler برای زمان‌بندی مناسب است و Queue برای پردازش‌های پس‌زمینه.


# Scheduler و Redis

Redis می‌تواند در معماری Scheduler نیز نقش داشته باشد؛ مخصوصاً زمانی که از Queue یا Cache مشترک استفاده می‌کنیم.

مثلاً:


Scheduler

   ↓

Job

   ↓

Redis Queue

   ↓

Worker

در این حالت Scheduler شروع‌کننده فرآیند است و Redis و Queue وظیفه انتقال و پردازش Job را بر عهده دارند.


# مثال واقعی: بررسی سرویس‌های منقضی‌شده

فرض کنید یک SaaS داریم و باید هر روز Subscriptionهای منقضی‌شده بررسی شوند.

می‌توانیم یک Command داشته باشیم:


php artisan make:command ProcessExpiredSubscriptions

سپس آن را روزانه اجرا کنیم:


Schedule::command('subscriptions:process-expired')

    ->dailyAt('00:30');

معماری:


00:30

  ↓

Laravel Scheduler

  ↓

subscriptions:process-expired

  ↓

Find expired subscriptions

  ↓

Update status

  ↓

Send notification

اگر عملیات سنگین باشد، بهتر است Command به جای پردازش مستقیم، Jobهای موردنیاز را Dispatch کند.


# مثال واقعی: دریافت نرخ ارز

فرض کنید سیستم شما هر 10 دقیقه باید نرخ ارز را از یک API دریافت کند.

می‌توانیم داشته باشیم:


Schedule::job(new UpdateCurrencyRates)

    ->everyTenMinutes();

و معماری:


Every 10 Minutes

       ↓

Scheduler

       ↓

UpdateCurrencyRates

       ↓

Queue

       ↓

Worker

       ↓

External API

       ↓

Database / Cache

این مدل برای پروژه‌هایی که با APIهای خارجی کار می‌کنند بسیار کاربردی است.


# مثال واقعی: پاک‌سازی داده‌های قدیمی

فرض کنید Log یا داده‌های موقتی زیادی در Database ایجاد می‌شوند.

می‌توان یک Command ساخت:


php artisan make:command CleanupOldData

و آن را زمان‌بندی کرد:


Schedule::command('data:cleanup')

    ->dailyAt('03:00');

در نتیجه سیستم بدون دخالت کاربر داده‌های قدیمی را پاک می‌کند.


# مثال واقعی: ارسال گزارش روزانه

فرض کنید هر روز صبح مدیر باید گزارش فروش دریافت کند.

می‌توان:


Schedule::job(new SendDailySalesReport)

    ->dailyAt('08:00');

استفاده کرد.

اگر Mail نیز در Queue قرار بگیرد:


Scheduler

    ↓

Job

    ↓

Queue

    ↓

Mail

این روش باعث می‌شود Scheduler درگیر ارسال مستقیم Email نشود.


# نکات مهم برای Taskهای حساس

برای Taskهایی که عملیات مالی یا حساس انجام می‌دهند باید دقت بیشتری داشته باشید.

مثلاً:


پرداخت

Billing

شارژ کیف پول

تمدید اشتراک

تغییر موجودی

نباید فقط به Scheduler اعتماد کنید.

منطق Application باید در برابر اجرای تکراری نیز مقاوم باشد.

یعنی حتی اگر Task به هر دلیلی دوبار اجرا شد، نباید عملیات مالی دوبار انجام شود.

برای چنین سیستم‌هایی باید از مواردی مانند:

  • Unique Constraint
  • Transaction
  • Lock
  • Idempotency
  • withoutOverlapping()

در جای مناسب استفاده کرد.


# Idempotency در Task Scheduling

فرض کنید Task زیر اجرا می‌شود:


Process Payment

اگر به هر دلیلی دو بار اجرا شود، نباید دو پرداخت ثبت شود.

پس بهتر است منطق Command یا Job به شکلی طراحی شود که اجرای مجدد آن نتیجه مخرب ایجاد نکند.

مثلاً قبل از انجام عملیات، وضعیت Transaction بررسی شود:


if ($transaction->isCompleted()) {

    return;

}

Scheduler فقط زمان اجرا را کنترل می‌کند.

امنیت و صحت عملیات باید داخل Business Logic نیز کنترل شود.


# جلوگیری از اجرای چندباره Cron

یکی از مشکلات رایج در سرور این است که یک Cron Job چند بار تعریف شده باشد.

مثلاً:


* * * * * php artisan schedule:run

* * * * * php artisan schedule:run

در چنین شرایطی ممکن است Scheduler چند بار در هر دقیقه اجرا شود.

بنابراین همیشه Cronهای سرور را بررسی کنید:


crontab -l

و مطمئن شوید Scheduler فقط به‌شکل موردنظر تعریف شده است.


# مشکلات رایج Laravel Scheduler

Task اجرا نمی‌شود

ابتدا:


php artisan schedule:list

را بررسی کنید.

سپس:


php artisan schedule:run

را به‌صورت دستی اجرا کنید.


Cron اجرا نمی‌شود

Cron را بررسی کنید:


crontab -l

و مطمئن شوید مسیر پروژه و PHP صحیح هستند.

مثلاً در بعضی سرورها php ممکن است به نسخه متفاوتی اشاره کند.

برای بررسی:


which php

php -v


مسیر پروژه اشتباه است

در Cron باید مسیر واقعی Laravel مشخص باشد:


* * * * * cd /path/to/laravel && php artisan schedule:run

اگر مسیر اشتباه باشد، Scheduler اجرا نمی‌شود.


Permission مشکل دارد

کاربری که Cron را اجرا می‌کند باید دسترسی لازم به پروژه و Storage را داشته باشد.

این موضوع مخصوصاً در سرورهای Production مهم است.


Task اجرا می‌شود اما Job پردازش نمی‌شود

اگر Scheduler یک Job را Dispatch کند ولی Queue Worker فعال نباشد:


Scheduler

   ↓

Job

   ↓

Queue

   ↓

❌ Worker

Job ممکن است در Queue باقی بماند.

پس در چنین معماری‌ای باید Scheduler و Queue Worker را جداگانه بررسی کنید.


# چک‌لیست راه‌اندازی Scheduler در Production

قبل از Deploy، این موارد را بررسی کنید:

1. Schedule تعریف شده است؟


php artisan schedule:list

2. Command دستی اجرا می‌شود؟


php artisan your:command

3. Scheduler دستی اجرا می‌شود؟


php artisan schedule:run

4. Cron وجود دارد؟


crontab -l

5. PHP صحیح استفاده می‌شود؟


php -v

6. مسیر پروژه صحیح است؟


/path/to/project

7. Permissionها صحیح هستند؟

8. اگر Job استفاده شده، Queue Worker فعال است؟


php artisan queue:work


# ساختار پیشنهادی برای پروژه‌های حرفه‌ای

در پروژه‌های بزرگ بهتر است Scheduler را تبدیل به محل نگهداری منطق تجاری نکنیم.

مثلاً این کار مناسب نیست:


Schedule::call(function () {

    // صدها خط Business Logic

})->daily();

بهتر است:


Scheduler

   ↓

Command / Job

   ↓

Service

   ↓

Business Logic

مثلاً:


Schedule::command('billing:process')

    ->daily();

و Business Logic داخل Command و Service قرار داشته باشد.

این ساختار باعث می‌شود:

  • تست آسان‌تر شود
  • کد خواناتر باشد
  • Command قابل اجرای دستی باشد
  • Business Logic از Scheduler جدا بماند

# بهترین روش برای نام‌گذاری Taskها

نام‌گذاری واضح بسیار مهم است.

به جای:


task1

task2

process

run

از نام‌های مشخص استفاده کنید:


billing:process-due

subscriptions:renew

reports:generate-daily

services:sync-status

notifications:send-reminders

data:cleanup

این کار در پروژه‌های بزرگ Debug کردن Scheduler را بسیار ساده‌تر می‌کند.


# Task Scheduling و پروژه‌های SaaS

در پروژه‌های SaaS معمولاً Scheduler کاربرد بسیار زیادی دارد.

مثلاً:


هر دقیقه:

بررسی وضعیت Jobها



هر 10 دقیقه:

همگام‌سازی اطلاعات



هر ساعت:

بررسی سرویس‌ها



هر روز:

Billing



هر هفته:

گزارش



هر ماه:

Invoice

یک ساختار واقعی می‌تواند این‌گونه باشد:


Laravel Scheduler

       │

       ├── Services Sync

       ├── Billing

       ├── Notifications

       ├── Reports

       ├── Cleanup

       └── Renewals

در پروژه‌های بزرگ‌تر بهتر است هر عملیات مهم به Command یا Job مستقل منتقل شود.


# جمع‌بندی

Task Scheduling یکی از قابلیت‌های مهم Laravel برای مدیریت عملیات‌های دوره‌ای است.

با Scheduler می‌توانیم اجرای مواردی مانند:

  • Artisan Command
  • Job
  • Closure
  • گزارش‌ها
  • Cleanup
  • Synchronization
  • Notification
  • Billing
  • دریافت اطلاعات API

را زمان‌بندی کنیم.

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


Cron

 ↓

schedule:run

 ↓

Laravel Scheduler

 ↓

Command / Job / Closure

 ↓

Execute

در پروژه‌های حرفه‌ای نیز بهتر است Scheduler فقط مسئول زمان‌بندی باشد و منطق اصلی در Command، Job و Service قرار بگیرد.

همچنین برای Taskهای حساس باید مواردی مانند withoutOverlapping، Lock، Idempotency و Transaction را متناسب با نیاز پروژه در نظر گرفت.


# سوالات متداول

Task Scheduling در Laravel چیست؟

Task Scheduling سیستم داخلی Laravel برای تعریف و مدیریت زمان اجرای وظایف مختلف مانند Command، Job و Closure است.

آیا Laravel Scheduler به Cron نیاز دارد؟

در روش معمول Production، بله. معمولاً یک Cron در سیستم‌عامل هر دقیقه php artisan schedule:run را اجرا می‌کند تا Laravel Scheduleهای موعددار را بررسی کند.

schedule:run چیست؟

این دستور Scheduleهای Laravel را بررسی می‌کند و Taskهایی را که زمان اجرای آنها رسیده است اجرا می‌کند.


php artisan schedule:run

schedule:work چیست؟

php artisan schedule:work Scheduler را به‌صورت مداوم اجرا می‌کند و برای Development و برخی معماری‌های Production کاربرد دارد.

چگونه یک Command را روزانه اجرا کنیم؟

مثلاً:


Schedule::command('report:generate')->daily();

چگونه یک Job را زمان‌بندی کنیم؟

مثلاً:


Schedule::job(new GenerateReport)->daily();

چگونه از اجرای همزمان یک Task جلوگیری کنیم؟

می‌توان از:


->withoutOverlapping()

استفاده کرد.

چگونه Scheduleهای Laravel را ببینیم؟

با:


php artisan schedule:list

می‌توانید Scheduleهای تعریف‌شده را بررسی کنید.

آیا Scheduler همان Queue است؟

خیر.

Scheduler مشخص می‌کند چه زمانی یک عملیات اجرا شود؛ Queue برای پردازش پس‌زمینه Jobها استفاده می‌شود.

نظرات (0)

نظرات پس از تأیید مدیر نمایش داده می‌شوند

هنوز نظری ثبت نشده است؛ اولین نفر باشید!

مقالات مرتبط

ساخت CMS با Laravel 12؛ آموزش ساخت سیستم مدیریت محتوا از صفر

ساخت CMS با Laravel 12؛ آموزش ساخت سیستم مدیریت محتوا از صفر

۲۴ دقیقه
ساخت فروشگاه اینترنتی با Laravel 12؛ آموزش پروژه‌محور از صفر تا طراحی هسته فروشگاه

ساخت فروشگاه اینترنتی با Laravel 12؛ آموزش پروژه‌محور از صفر تا طراحی هسته فروشگاه

۲۲ دقیقه
ساخت Marketplace با Laravel؛ آموزش طراحی فروشگاه چندفروشندگی

ساخت Marketplace با Laravel؛ آموزش طراحی فروشگاه چندفروشندگی

۲۲ دقیقه
مدیریت Queueهای سنگین در Laravel؛ آموزش پردازش کارهای طولانی

مدیریت Queueهای سنگین در Laravel؛ آموزش پردازش کارهای طولانی

۲۲ دقیقه