Версія фреймворка: 8.x

Планування завдань

Вступ

Раніше ви могли створювати запис Cron для кожного завдання, яке вам потрібно було запланувати на своєму сервері. Однак це може швидко стати проблемою, оскільки ваш графік завдань більше не контролюється джерелом, і ви повинні SSH на своєму сервері, щоб додати додаткові записи Cron.

Планувальник команд Laravel дозволяє вам вільно та виразно визначити свій графік команд у самому Laravel. При використанні планувальника на вашому сервері потрібен лише один запис Cron. Розклад ваших завдань визначений уapp/Console/Kernel.phpфайлівscheduleметод. Щоб допомогти вам розпочати, у методі визначено простий приклад.

Запуск планувальника

При використанні планувальника вам потрібно лише додати наступний запис Cron на ваш сервер. Якщо ви не знаєте, як додати записи Cron на свій сервер, подумайте про використання такої послуги, якКузня Laravelякий може керувати записами Cron для вас:

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

Цей Cron щохвилини телефонуватиме до планувальника команд Laravel. Колиschedule:runкоманда виконується, Laravel оцінить ваші заплановані завдання та виконає відповідні завдання.

Запуск планувальника локально

Як правило, ви не додаєте запис планувальника Cron до вашої локальної машини розробки. Натомість ви можете використовуватиschedule:workArtisan командування. Ця команда буде виконуватися на передньому плані та викликати планувальник щохвилини, поки ви не вийдете з команди:

php artisan schedule:work

Визначення графіків

Ви можете визначити всі заплановані завдання вscheduleметодApp\Console\Kernelклас. Для початку давайте розглянемо приклад планування завдання. У цьому прикладі ми заплануємо aClosureдзвонити щодня опівночі. У межахClosureми виконаємо запит до бази даних для очищення таблиці:

<?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
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        //
    ];

    /**
     * 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();
    }
}

Окрім планування за допомогою Closures, ви також можете використовувативикликаються об'єкти. Невідкличні об'єкти - це прості класи PHP, які містять__invokeметод:

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

Планування команд ремісників

На додаток до планування дзвінків на закриття, ви також можете заплануватиРемісничі командита команди операційної системи. Наприклад, ви можете використовуватиcommandспосіб запланувати команду Artisan, використовуючи або назву команди, або клас:

$schedule->command('emails:send Taylor --force')->daily();

$schedule->command(EmailsCommand::class, ['Taylor', '--force'])->daily();

Планування роботи в черзі

jobметод може бути використаний для планування aробота в черзі. Цей метод забезпечує зручний спосіб планування робіт без використанняcallспосіб вручну створити Закриття для черги на завдання:

$schedule->job(new Heartbeat)->everyFiveMinutes();

// Dispatch the job to the "heartbeats" queue...
$schedule->job(new Heartbeat, 'heartbeats')->everyFiveMinutes();

Планування команд оболонки

execметод може бути використаний для видачі команди операційній системі:

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

Заплануйте параметри частоти

Існує безліч графіків, які ви можете призначити для свого завдання:

Метод Опис
->cron('* * * * *'); Запускає завдання за власним розкладом Cron
->everyMinute(); Запускає завдання щохвилини
->everyTwoMinutes(); Запускає завдання кожні дві хвилини
->everyThreeMinutes(); Запускає завдання кожні три хвилини
->everyFourMinutes(); Запускає завдання кожні чотири хвилини
->everyFiveMinutes(); Запускає завдання кожні п’ять хвилин
->everyTenMinutes(); Запускає завдання кожні десять хвилин
->everyFifteenMinutes(); Запускає завдання кожні п’ятнадцять хвилин
->everyThirtyMinutes(); Запускає завдання кожні тридцять хвилин
->hourly(); Запускає завдання щогодини
->hourlyAt(17); Запускає завдання кожну годину о 17 хвилинах за годину
->everyTwoHours(); Запускає завдання кожні дві години
->everyThreeHours(); Запускає завдання кожні три години
->everyFourHours(); Запускає завдання кожні чотири години
->everySixHours(); Запускає завдання кожні шість годин
->daily(); Запускає завдання щодня опівночі
->dailyAt('13:00'); Запускає завдання щодня о 13:00
->twiceDaily(1, 13); Запускає завдання щодня о 1:00 та 13:00
->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
->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(); Обмежте завдання суботою
`-> дні (масив змішаний); ` Обмежте завдання конкретними днями
->between($startTime, $endTime); Обмежте завдання для запуску між часом початку та кінця
->unlessBetween($startTime, $endTime); Обмежте завдання не запускатись між часом початку та кінця
->when(Closure); Обмежте завдання на основі перевірки істини
->environments($env); Обмежте завдання конкретним середовищем

Денні обмеження

daysметод може бути використаний для обмеження виконання завдання певними днями тижня. Наприклад, ви можете запланувати команду для запуску щогодини в неділю та середу:

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

Між часовими обмеженнями

betweenметод може бути використаний для обмеження виконання завдання на основі часу доби:

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

Подібним чиномunlessBetweenметод може бути використаний для виключення виконання завдання протягом певного періоду:

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

Обмеження перевірки істини

whenметод може бути використаний для обмеження виконання завдання на основі результату даного тесту на істинність. Іншими словами, якщо данеClosureповертається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метод може бути використаний для виконання завдань лише в заданих середовищах:

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

Часові зони

Використанняtimezoneметодом, ви можете вказати, що час запланованого завдання повинен інтерпретуватися в межах заданого часового поясу:

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

Якщо ви призначаєте однаковий часовий пояс усім запланованим завданням, можливо, ви захочете визначитиscheduleTimezoneметод у вашомуapp/Console/Kernel.phpфайл. Цей метод повинен повертати часовий пояс за замовчуванням, який повинен бути призначений для всіх запланованих завдань:

/**
 * 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:sendArtisan командуваннябуде запускатися щохвилини, якщо вона ще не працює.withoutOverlappingметод особливо корисний, якщо у вас є завдання, які різко різняться за часом виконання, не даючи вам точно передбачити, скільки часу триватиме дане завдання.

При необхідності ви можете вказати, скільки хвилин має пройти до закінчення терміну дії "без перекриття". За замовчуванням блокування закінчується через 24 години:

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

Запуск завдань на одному сервері

Щоб використовувати цю функцію, ваша програма повинна використовуватиdatabase,memcached, абоredisкеш-драйвер як драйвер кешу вашого додатка за замовчуванням. Крім того, усі сервери повинні взаємодіяти з одним сервером центральної кеш-пам’яті.

Якщо ваша програма працює на декількох серверах, ви можете обмежити заплановане завдання лише на одному сервері. Наприклад, припустимо, що у вас є заплановане завдання, яке генерує новий звіт щоп’ятниці ввечері. Якщо планувальник завдань працює на трьох робочих серверах, заплановане завдання буде виконуватися на всіх трьох серверах і тричі генеруватиме звіт. Не добре!

Щоб вказати, що завдання має виконуватися лише на одному сервері, використовуйтеonOneServerметод при визначенні запланованого завдання. Перший сервер, який отримає завдання, забезпечить атомний замок завдання, щоб запобігти одночасному виконанню того самого завдання на інших серверах:

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

Фонові завдання

За замовчуванням кілька команд, запланованих одночасно, будуть виконуватися послідовно. Якщо у вас є тривалі команди, це може спричинити запуск наступних команд набагато пізніше, ніж передбачалося. Якщо ви хочете запускати команди у фоновому режимі, щоб усі вони могли працювати одночасно, ви можете використовуватиrunInBackgroundметод:

$schedule->command('analytics:report')
         ->daily()
         ->runInBackground();
runInBackgroundметод може використовуватися лише при плануванні завдань черезcommandіexecметоди.

Режим обслуговування

Заплановані завдання Laravel не запускатимуться, коли Laravel працюєрежим обслуговування, оскільки ми не хочемо, щоб ваші завдання заважали незавершеному обслуговуванню, яке ви можете виконувати на своєму сервері. Однак, якщо ви хочете змусити запустити завдання навіть у режимі обслуговування, ви можете використовуватиevenInMaintenanceModeметод:

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

Вихід завдання

Планувальник Laravel надає кілька зручних методів для роботи з результатом, що генерується запланованими завданнями. По-перше, за допомогоюsendOutputToметодом, ви можете надіслати вихідні дані у файл для подальшої перевірки:

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

Якщо ви хочете додати вихідні дані до даного файлу, ви можете використовувати файлappendOutputToметод:

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

ВикористанняemailOutputToВи можете надіслати вихідні дані на електронну адресу за вашим вибором. Перш ніж надсилати вихідні дані завдання електронною поштою, слід налаштувати Laravelпослуги електронної пошти:

$schedule->command('foo')
         ->daily()
         ->sendOutputTo($filePath)
         ->emailOutputTo('foo@example.com');

Якщо ви хочете надіслати вихідні дані лише електронною поштою, якщо команда не вдається, використовуйтеemailOutputOnFailureметод:

$schedule->command('foo')
         ->daily()
         ->emailOutputOnFailure('foo@example.com');
emailOutputTo,emailOutputOnFailure,sendOutputTo, іappendOutputToметоди є ексклюзивними дляcommandіexecметоди.

Гачки завдань

Використанняbeforeіafterметодами, ви можете вказати код, який буде виконуватися до і після завершення запланованого завдання:

$schedule->command('emails:send')
         ->daily()
         ->before(function () {
             // Task is about to start...
         })
         ->after(function () {
             // Task is complete...
         });

onSuccessіonFailureМетоди дозволяють вказати код, який буде виконуватися, якщо заплановане завдання вдається або не вдається:

$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-адресу до або після завершення завдання. Цей метод корисний для сповіщення зовнішньої служби, наприкладLaravel Send, що ваше заплановане завдання розпочинається або завершило виконання:

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

pingBeforeIfіthenPingIfМетоди можуть бути використані для пінгування даної URL-адреси, лише якщо задана умоваtrue:

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

pingOnSuccessіpingOnFailureМетоди можуть бути використані для пінгування даної URL-адреси, лише якщо завдання успішне або не вдається:

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

Для всіх методів ping потрібна бібліотека Guzzle HTTP. Ви можете додати Guzzle до свого проекту за допомогою менеджера пакетів Composer:

composer require guzzlehttp/guzzle