نسخه:

برنامه ریزی وظایف

معرفی

در گذشته، ممکن است یک ورودی پیکربندی cron برای هر کاری که نیاز به برنامه ریزی روی سرور خود داشتید، نوشته باشید. با این حال، این می تواند به سرعت تبدیل به یک دردسر شود زیرا برنامه کاری شما دیگر در کنترل منبع نیست و باید برای مشاهده ورودی های cron موجود یا اضافه کردن ورودی های اضافی، SSH را به سرور خود وارد کنید.

زمانبندی فرمان لاراول یک رویکرد جدید برای مدیریت وظایف برنامه ریزی شده در سرور شما ارائه می دهد. زمان‌بند به شما اجازه می‌دهد تا به‌طور روان و واضح برنامه دستورات خود را در خود برنامه لاراول تعریف کنید. هنگام استفاده از زمانبندی، تنها یک ورودی cron در سرور شما مورد نیاز است. برنامه کاری شما در روش app/Console/Kernel.php فایل تعریف شده است schedule . برای کمک به شروع، یک مثال ساده در داخل متد تعریف شده است.

تعریف برنامه ها

شما می توانید تمام وظایف برنامه ریزی شده خود را در schedule متد کلاس برنامه خود تعریف کنید App\Console\Kernel . برای شروع، بیایید به یک مثال نگاه کنیم. در این مثال، ما تعطیلی را برنامه ریزی می کنیم تا هر روز در نیمه شب تماس گرفته شود. در بسته شدن، یک کوئری پایگاه داده را برای پاک کردن جدول اجرا می کنیم:

<?php
 
namespace App\Console;
 
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Illuminate\Support\Facades\DB;
 
class Kernel extends ConsoleKernel
{
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->call(function () {
DB::table('recent_users')->delete();
})->daily();
}
}

علاوه بر زمان‌بندی با استفاده از بسته‌ها، می‌توانید اشیاء قابل فراخوانی را نیز برنامه‌ریزی کنید . اشیای فراخوانی کلاس های PHP ساده ای هستند که حاوی __invoke متد زیر هستند:

$schedule->call(new DeleteRecentUsers)->daily();

اگر می خواهید یک نمای کلی از وظایف برنامه ریزی شده خود و دفعه بعدی که قرار است اجرا شوند، مشاهده کنید، می توانید از schedule:list دستور Artisan استفاده کنید:

php artisan schedule:list

زمانبندی دستورات صنعتگر

علاوه بر زمان‌بندی بسته شدن، می‌توانید دستورات Artisan و دستورات سیستم را نیز برنامه‌ریزی کنید. برای مثال، می‌توانید از command روشی برای زمان‌بندی دستور Artisan با استفاده از نام یا کلاس دستور استفاده کنید.

هنگام برنامه‌ریزی دستورات Artisan با استفاده از نام کلاس دستور، می‌توانید آرایه‌ای از آرگومان‌های خط فرمان اضافی را ارسال کنید که باید هنگام فراخوانی فرمان به آن ارائه شود:

use App\Console\Commands\SendEmailsCommand;
 
$schedule->command('emails:send Taylor --force')->daily();
 
$schedule->command(SendEmailsCommand::class, ['Taylor', '--force'])->daily();

زمان بندی مشاغل در صف

این job روش ممکن است برای برنامه ریزی یک کار در صف استفاده شود . این روش روشی مناسب برای برنامه‌ریزی مشاغل در صف بدون استفاده از call روش تعریف بسته‌ها برای صف‌بندی کار فراهم می‌کند:

use App\Jobs\Heartbeat;
 
$schedule->job(new Heartbeat)->everyFiveMinutes();

آرگومان های دوم و سوم اختیاری ممکن است به روشی ارائه شود job که نام صف و اتصال صف را که باید برای صف بندی کار استفاده شود، مشخص می کند:

use App\Jobs\Heartbeat;
 
// Dispatch the job to the "heartbeats" queue on the "sqs" connection...
$schedule->job(new Heartbeat, 'heartbeats', 'sqs')->everyFiveMinutes();

زمان بندی دستورات شل

این exec روش ممکن است برای صدور فرمان به سیستم عامل استفاده شود:

$schedule->exec('node /home/forge/script.js')->daily();

گزینه های فرکانس را برنامه ریزی کنید

ما قبلاً چند نمونه از نحوه پیکربندی یک کار را برای اجرا در فواصل زمانی مشخص دیده‌ایم. با این حال، فرکانس‌های زمان‌بندی وظایف بسیار بیشتری وجود دارد که می‌توانید به یک کار اختصاص دهید:

روش شرح
->cron('* * * * *'); وظیفه را بر روی یک برنامه cron سفارشی اجرا کنید
->everyMinute(); هر دقیقه کار را اجرا کنید
->everyTwoMinutes(); کار را هر دو دقیقه یکبار اجرا کنید
->everyThreeMinutes(); کار را هر سه دقیقه یکبار اجرا کنید
->everyFourMinutes(); کار را هر چهار دقیقه یکبار اجرا کنید
->everyFiveMinutes(); کار را هر پنج دقیقه یکبار اجرا کنید
->everyTenMinutes(); کار را هر ده دقیقه یکبار اجرا کنید
->everyFifteenMinutes(); کار را هر پانزده دقیقه اجرا کنید
->everyThirtyMinutes(); کار را هر سی دقیقه یکبار اجرا کنید
->hourly(); هر ساعت کار را اجرا کنید
->hourlyAt(17); این کار را هر ساعت 17 دقیقه قبل از ساعت اجرا کنید
->everyOddHour(); کار را هر ساعت فرد اجرا کنید
->everyTwoHours(); کار را هر دو ساعت یکبار اجرا کنید
->everyThreeHours(); کار را هر سه ساعت یکبار اجرا کنید
->everyFourHours(); هر چهار ساعت یک بار کار را اجرا کنید
->everySixHours(); این کار را هر شش ساعت یکبار اجرا کنید
->daily(); کار را هر روز در نیمه شب اجرا کنید
->dailyAt('13:00'); کار را هر روز ساعت 13:00 اجرا کنید
->twiceDaily(1, 13); کار را هر روز در ساعت 1:00 و 13:00 اجرا کنید
->twiceDailyAt(1, 13, 15); کار را روزانه در ساعت 1:15 و 13:15 اجرا کنید
->weekly(); هر یکشنبه ساعت 00:00 این کار را اجرا کنید
->weeklyOn(1, '8:00'); کار را هر هفته دوشنبه ساعت 8:00 اجرا کنید
->monthly(); کار را در روز اول هر ماه ساعت 00:00 اجرا کنید
->monthlyOn(4, '15:00'); کار را هر ماه در تاریخ 4 ساعت 15:00 اجرا کنید
->twiceMonthly(1, 16, '13:00'); کار را ماهانه در روزهای 1 و 16 ساعت 13:00 اجرا کنید
->lastDayOfMonth('15:00'); در آخرین روز ماه ساعت 15:00 کار را اجرا کنید
->quarterly(); کار را در روز اول هر سه ماهه ساعت 00:00 اجرا کنید
->quarterlyOn(4, '14:00'); این کار را هر سه ماهه چهارم در ساعت 14:00 انجام دهید
->yearly(); کار را در اولین روز هر سال ساعت 00:00 انجام دهید
->yearlyOn(6, 1, '17:00'); این کار را هر سال در 1 ژوئن ساعت 17:00 اجرا کنید
->timezone('America/New_York'); منطقه زمانی کار را تنظیم کنید

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

// Run once per week on Monday at 1 PM...
$schedule->call(function () {
//
})->weekly()->mondays()->at('13:00');
 
// Run hourly from 8 AM to 5 PM on weekdays...
$schedule->command('foo')
->weekdays()
->hourly()
->timezone('America/Chicago')
->between('8:00', '17:00');

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

روش شرح
->weekdays(); کار را به روزهای هفته محدود کنید
->weekends(); کار را به آخر هفته ها محدود کنید
->sundays(); کار را به یکشنبه محدود کنید
->mondays(); کار را به دوشنبه محدود کنید
->tuesdays(); کار را به سه شنبه محدود کنید
->wednesdays(); کار را به چهارشنبه محدود کنید
->thursdays(); کار را به پنجشنبه محدود کنید
->fridays(); کار را به جمعه محدود کنید
->saturdays(); کار را به شنبه محدود کنید
->days(array|mixed); کار را به روزهای خاصی محدود کنید
->between($startTime, $endTime); کار را بین زمان شروع و پایان محدود کنید
->unlessBetween($startTime, $endTime); کار را محدود کنید تا بین زمان شروع و پایان اجرا نشود
->when(Closure); کار را بر اساس آزمون حقیقت محدود کنید
->environments($env); کار را به محیط های خاص محدود کنید

محدودیت های روز

این days روش ممکن است برای محدود کردن اجرای یک کار به روزهای خاصی از هفته استفاده شود. برای مثال، می‌توانید دستوری را برای اجرای ساعتی در روزهای یکشنبه و چهارشنبه برنامه‌ریزی کنید:

$schedule->command('emails:send')
->hourly()
->days([0, 3]);

از طرف دیگر، می‌توانید از ثابت‌های موجود در Illuminate\Console\Scheduling\Schedule کلاس هنگام تعیین روزهایی که یک وظیفه باید اجرا شود استفاده کنید:

use Illuminate\Console\Scheduling\Schedule;
 
$schedule->command('emails:send')
->hourly()
->days([Schedule::SUNDAY, Schedule::WEDNESDAY]);

بین محدودیت های زمانی

این between روش ممکن است برای محدود کردن اجرای یک کار بر اساس زمان روز استفاده شود:

$schedule->command('emails:send')
->hourly()
->between('7:00', '22:00');

به طور مشابه، این unlessBetween روش می تواند برای حذف اجرای یک کار برای یک دوره زمانی استفاده شود:

$schedule->command('emails:send')
->hourly()
->unlessBetween('23:00', '4:00');

محدودیت های آزمون حقیقت

این when روش ممکن است برای محدود کردن اجرای یک کار بر اساس نتیجه یک آزمون صدق داده شده استفاده شود. به عبارت دیگر، اگر بسته شدن داده شده برگردد true ، تا زمانی که هیچ شرایط محدود کننده دیگری از اجرای وظیفه جلوگیری نکند، وظیفه اجرا خواهد شد:

$schedule->command('emails:send')->daily()->when(function () {
return true;
});

روش skip ممکن است به صورت معکوس دیده شود when . اگر skip متد برگردد true ، وظیفه برنامه ریزی شده اجرا نمی شود:

$schedule->command('emails:send')->daily()->skip(function () {
return true;
});

هنگام استفاده از when روش‌های زنجیره‌ای، دستور زمان‌بندی شده تنها در صورتی اجرا می‌شود که همه when شرایط برگردند true .

محدودیت های محیطی

این environments روش ممکن است فقط برای اجرای وظایف در محیط های داده شده (همانطور که توسط APP_ENV متغیر محیطی تعریف شده است ) استفاده شود:

$schedule->command('emails:send')
->daily()
->environments(['staging', 'production']);

محدوده های زمانی

با استفاده از timezone روش، می توانید تعیین کنید که زمان یک کار برنامه ریزی شده باید در یک منطقه زمانی معین تفسیر شود:

$schedule->command('report:generate')
->timezone('America/New_York')
->at('2:00')

اگر به طور مکرر منطقه زمانی یکسانی را به همه وظایف برنامه ریزی شده خود اختصاص می دهید، ممکن است بخواهید یک scheduleTimezone متد را در App\Console\Kernel کلاس خود تعریف کنید. این روش باید منطقه زمانی پیش‌فرض را که باید به همه وظایف زمان‌بندی شده اختصاص داده شود، برگرداند:

/**
* Get the timezone that should be used by default for scheduled events.
*
* @return \DateTimeZone|string|null
*/
protected function scheduleTimezone()
{
return 'America/Chicago';
}

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

جلوگیری از همپوشانی وظایف

به‌طور پیش‌فرض، حتی اگر نمونه قبلی کار هنوز در حال اجرا باشد، کارهای برنامه‌ریزی‌شده اجرا می‌شوند. برای جلوگیری از این، می توانید از withoutOverlapping روش زیر استفاده کنید:

$schedule->command('emails:send')->withoutOverlapping();

در این مثال، اگر emails:send دستور Artisan از قبل اجرا نشده باشد، هر دقیقه اجرا می شود. این withoutOverlapping روش مخصوصاً زمانی مفید است که وظایفی دارید که زمان اجرای آنها به شدت متفاوت است و شما را از پیش بینی دقیق مدت زمان انجام یک کار باز می دارد.

در صورت نیاز، می‌توانید تعیین کنید که چند دقیقه باید تا پایان قفل "بدون همپوشانی" بگذرد. به طور پیش فرض، قفل پس از 24 ساعت منقضی می شود:

$schedule->command('emails:send')->withoutOverlapping(10);

در پشت صحنه، این روش از کش withoutOverlapping برنامه شما برای به دست آوردن قفل استفاده می کند. در صورت لزوم می توانید این قفل های کش را با استفاده از دستور Artisan پاک کنید. این معمولاً فقط در صورتی ضروری است که یک کار به دلیل یک مشکل غیرمنتظره سرور گیر کند. schedule:clear-cache

اجرای وظایف روی یک سرور

برای استفاده از این ویژگی، برنامه شما باید از database , memcached , dynamodb یا redis کش به عنوان درایور کش پیش فرض برنامه شما استفاده کند. علاوه بر این، همه سرورها باید با یک سرور حافظه مرکزی یکسان در ارتباط باشند.

اگر زمان‌بندی برنامه شما روی چندین سرور اجرا می‌شود، می‌توانید یک کار زمان‌بندی‌شده را به اجرای تنها روی یک سرور محدود کنید. به عنوان مثال، فرض کنید یک کار برنامه ریزی شده دارید که هر جمعه شب یک گزارش جدید تولید می کند. اگر زمان‌بندی کار روی سه سرور کارگر اجرا شود، وظیفه برنامه‌ریزی‌شده روی هر سه سرور اجرا می‌شود و گزارش را سه بار تولید می‌کند. خوب نیست!

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

$schedule->command('report:generate')
->fridays()
->at('17:00')
->onOneServer();

نامگذاری مشاغل تک سرور

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

$schedule->job(new CheckUptime('https://laravel.com'))
->name('check_uptime:laravel.com')
->everyFiveMinutes()
->onOneServer();
 
$schedule->job(new CheckUptime('https://vapor.laravel.com'))
->name('check_uptime:vapor.laravel.com')
->everyFiveMinutes()
->onOneServer();

به طور مشابه، بسته‌های برنامه‌ریزی‌شده اگر قرار است روی یک سرور اجرا شوند، باید یک نام اختصاص دهند:

$schedule->call(fn () => User::resetApiRequestCount())
->name('reset-api-request-count')
->daily()
->onOneServer();

وظایف پس زمینه

به طور پیش فرض، چندین کار برنامه ریزی شده به طور همزمان بر اساس ترتیبی که در schedule روش شما تعریف شده اند به صورت متوالی اجرا می شوند. اگر کارهای طولانی مدت دارید، ممکن است باعث شود کارهای بعدی خیلی دیرتر از زمان پیش بینی شده شروع شوند. اگر می‌خواهید وظایف را در پس‌زمینه اجرا کنید تا همه آنها به طور همزمان اجرا شوند، می‌توانید از runInBackground روش زیر استفاده کنید:

$schedule->command('analytics:report')
->daily()
->runInBackground();

این runInBackground روش فقط می‌تواند هنگام زمان‌بندی کارها از طریق متدهای command و استفاده شود exec .

حالت تعمیر و نگهداری

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

$schedule->command('emails:send')->evenInMaintenanceMode();

اجرای برنامه زمانبندی

اکنون که نحوه تعریف وظایف برنامه ریزی شده را آموختیم، بیایید نحوه اجرای واقعی آنها را در سرور خود مورد بحث قرار دهیم. دستور schedule:run Artisan تمام کارهای برنامه ریزی شده شما را ارزیابی می کند و تعیین می کند که آیا آنها باید بر اساس زمان فعلی سرور اجرا شوند یا خیر.

بنابراین، هنگام استفاده از زمان‌بندی لاراول، فقط باید یک ورودی پیکربندی cron را به سرور خود اضافه کنیم که schedule:run هر دقیقه دستور را اجرا می‌کند. اگر نمی دانید چگونه ورودی های cron را به سرور خود اضافه کنید، از سرویسی مانند Laravel Forge استفاده کنید که می تواند ورودی های cron را برای شما مدیریت کند:

* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

اجرای برنامه زمانبندی به صورت محلی

به طور معمول، ورودی cron زمانبندی را به ماشین توسعه محلی خود اضافه نمی کنید. در عوض، می توانید از schedule:work دستور Artisan استفاده کنید. این دستور در پیش زمینه اجرا می شود و هر دقیقه زمانبندی را فراخوانی می کند تا زمانی که دستور را خاتمه دهید:

php artisan schedule:work

خروجی وظیفه

زمانبند لاراول چندین روش راحت را برای کار با خروجی تولید شده توسط وظایف برنامه ریزی شده ارائه می دهد. ابتدا، با استفاده از sendOutputTo روش، می توانید خروجی را برای بررسی بعدی به یک فایل ارسال کنید:

$schedule->command('emails:send')
->daily()
->sendOutputTo($filePath);

اگر می خواهید خروجی را به یک فایل معین اضافه کنید، می توانید از appendOutputTo روش زیر استفاده کنید:

$schedule->command('emails:send')
->daily()
->appendOutputTo($filePath);

با استفاده از این emailOutputTo روش، می توانید خروجی را به آدرس ایمیل دلخواه خود ایمیل کنید. قبل از ارسال ایمیل خروجی یک کار، باید سرویس های ایمیل لاراول را پیکربندی کنید :

$schedule->command('report:generate')
->daily()
->sendOutputTo($filePath)
->emailOutputTo('taylor@example.com');

اگر می‌خواهید خروجی را فقط در صورتی ایمیل کنید که فرمان زمان‌بندی شده Artisan یا سیستم با یک کد خروج غیر صفر خاتمه یابد، از emailOutputOnFailure روش زیر استفاده کنید:

$schedule->command('report:generate')
->daily()
->emailOutputOnFailure('taylor@example.com');

روش های emailOutputTo , emailOutputOnFailure , sendOutputTo , و appendOutputTo منحصر به روش command و هستند exec .

قلاب های وظیفه

با استفاده از before و after متدها، می توانید کدی را مشخص کنید که قبل و بعد از اجرای وظیفه برنامه ریزی شده اجرا شود:

$schedule->command('emails:send')
->daily()
->before(function () {
// The task is about to execute...
})
->after(function () {
// The task has executed...
});

متدهای onSuccess و onFailure به شما این امکان را می دهند که کدی را مشخص کنید که در صورت موفقیت یا شکست کار برنامه ریزی شده اجرا شود. خرابی نشان می دهد که دستور Artisan یا سیستم برنامه ریزی شده با یک کد خروج غیر صفر خاتمه یافته است:

$schedule->command('emails:send')
->daily()
->onSuccess(function () {
// The task succeeded...
})
->onFailure(function () {
// The task failed...
});

اگر خروجی از دستور شما در دسترس است، می‌توانید با تایپ کردن یک نمونه به عنوان آرگومان تعریف بسته شدن قلاب after ، به آن در قلاب onSuccess یا قلاب خود دسترسی پیدا کنید: onFailure Illuminate\Support\Stringable $output

use Illuminate\Support\Stringable;
 
$schedule->command('emails:send')
->daily()
->onSuccess(function (Stringable $output) {
// The task succeeded...
})
->onFailure(function (Stringable $output) {
// The task failed...
});

پینگ کردن URL ها

با استفاده از pingBefore و thenPing متدها، زمان‌بند می‌تواند به طور خودکار یک URL داده شده را قبل یا بعد از اجرای یک کار پینگ کند. این روش برای اطلاع رسانی به یک سرویس خارجی مانند Envoyer مفید است که کار برنامه ریزی شده شما شروع شده یا اجرای آن به پایان رسیده است:

$schedule->command('emails:send')
->daily()
->pingBefore($url)
->thenPing($url);

روش‌های pingBeforeIf و thenPingIf تنها در صورتی می‌توانند برای پینگ کردن یک URL معین استفاده شوند که یک شرط مشخص باشد true :

$schedule->command('emails:send')
->daily()
->pingBeforeIf($condition, $url)
->thenPingIf($condition, $url);

تنها در صورت موفقیت یا عدم موفقیت کار، می‌توان از روش‌های و برای پینگ کردن یک URL معین استفاده کرد pingOnSuccess . pingOnFailure خرابی نشان می دهد که دستور Artisan یا سیستم برنامه ریزی شده با یک کد خروج غیر صفر خاتمه یافته است:

$schedule->command('emails:send')
->daily()
->pingOnSuccess($successUrl)
->pingOnFailure($failureUrl);

همه روش‌های پینگ به کتابخانه HTTP Guzzle نیاز دارند. Guzzle معمولاً در تمام پروژه‌های Laravel جدید به طور پیش‌فرض نصب می‌شود، اما، اگر به‌طور تصادفی حذف شده باشد، می‌توانید Guzzle را با استفاده از مدیر بسته Composer به صورت دستی در پروژه خود نصب کنید:

composer require guzzlehttp/guzzle

مناسبت ها

در صورت نیاز، می توانید به رویدادهای ارسال شده توسط زمانبندی گوش دهید. به طور معمول، نگاشت شنونده رویداد در کلاس برنامه شما تعریف می شود App\Providers\EventServiceProvider :

/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'Illuminate\Console\Events\ScheduledTaskStarting' => [
'App\Listeners\LogScheduledTaskStarting',
],
 
'Illuminate\Console\Events\ScheduledTaskFinished' => [
'App\Listeners\LogScheduledTaskFinished',
],
 
'Illuminate\Console\Events\ScheduledBackgroundTaskFinished' => [
'App\Listeners\LogScheduledBackgroundTaskFinished',
],
 
'Illuminate\Console\Events\ScheduledTaskSkipped' => [
'App\Listeners\LogScheduledTaskSkipped',
],
 
'Illuminate\Console\Events\ScheduledTaskFailed' => [
'App\Listeners\LogScheduledTaskFailed',
],
];