Расписание заданий

Содержание:


Введение

В прошом, вам необходимо было добавлять запись Cron для каждого задания в расписании на вашем сервере. Очень быстро становится проблемой, потому что ваше расписание заданий не находится в системе управления версиями и вам необходимо подключаться по SSH и добавлять задания Cron на сервере.

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

Запуск планировщика.

При использовании планировщика, ваш лишь нужно добавить запись Cron на ваш сервер. Если вы не знаете как добавлять записи Cron на ваш сервер, можно воспользоваться сервисом Laravel Forge, который настроить записи Cron за вас:

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

Этот Cron будет вызывать каманду планироовщика Laravel каждую минуту. При выполнении команды schedule:run Ларавел просмотрит все команды и выполнит те задания, которые необоходимо.


Определение расписания

Вы можете определить все ваши запалнированные задания в методе 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
{
    /**
     * 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();
    }
}

Также можно использовать вызываемые объекты. Вызываемые объекты — это такие простые классы PHP, которые содержат метод __invoke:

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

Расписание Artisan команд

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

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

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

Расписание очередей заданий

Метод job может быть использован для планирования очередей заданий. Этот метод обеспечивает удобный способ запланировать задание без использования метода 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(); Выполняет задание каждую минуту
->everyFiveMinutes(); Выполнять задание каждые 5 минут
->everyTenMinutes(); Выполнять задание каждые 10 минут
->everyFifteenMinutes(); Выполнять задание каждые 15 минут
->everyThirtyMinutes(); Выполнять задание какждые 30 минут
->hourly(); Выполнять задание каждый час
->hourlyAt(17); Выполнять задание каждый час после 17-ой минуты
->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
->quarterly(); Выполнять задание в первый день каждого квартала в 00:00
->yearly(); Выполнять задание в первый день каждого года в 00: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($start, $end); Ограничить выполнение задачи временными интревалами
->when(Closure); Выполнять после теста на истину
->environments($env); Привязать выполение задачи к определённму окружению

Между временных интервалов

Метод code>between можно использовать, чтобы ограничить выполнение задания промежутком времени дня:

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

Аналогично, метод unlessBetween можно использовать, чтобы исключить промежуток времени:

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

Ограничения тестом на истину

Метод when может быть использован для того, чтобы ограничить выполнение задания в зависимости от результатом теста. Другими словами, если данное Замыкание вернёт true, и не будет других ограничений, задание будет выполняться:

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

Метод skip можно рассматривать как инверсию code>when. Если вернётся 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:send будет выполняться каждую минуту, если нет запущенных. Метод withoutOverlapping может быть особенно полезен, если у вас задания, диапазон времени выполнения может сильно колебаться, что мешает точно предсказать сколько времени займёт выполнение этого задания.

Если необходимо, вы можете указать как много минут должно пройти до момента, когда "without overlapping" наложит ограничения. По умолчанию, запрет пропадает через 24 часа:

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

Запуск заданий на одном сервере

Для применения этой возможности, ваше приложение должно использовать драйвер memcached или redis в качестве драйвера по умолчанию. Дополнительно, все сервера должны быть соединены с одним центральным сервером кэша.

Если ваше приложение запущено на нескольких серверах, вы можете ограничить планирование заданий таким образом, чтобы оно выполнялось только на одном серевере. Предполжим, у вас есть запланированное задание, которое генерирует новый отчёт в полночь каждой пятницы. Если планировщик запущен на трёх серверах, запланированное задание будет выполняться на всех трёх серверах и сгенерирует отчёт 3 раза. А это плохо.

Чтобы показать, что задание должно выполнять только на одном сервере, используйте метод onOneServer при определении запланированного задания. Первый сервер, который получит задание, наложит запрет на него, чтобы предотвратить выполнение одного задания в одно и тоже время другими серверами:

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

Фоновые задачи

По умолчанию, несколько запланированных на одно и тоже время будут выполнять последовательно. Если у вас есть команды требующие большого времени выполнения, то это может привести к тому, что последовательная команда будет запущена намного позже, чем ожидалось. Чтобы запустить команду в фоновом режиме, для одновременного выполения команд, вы можете использовать метод runInBackground:

$schedule->command('analytics:report')
         ->daily()
         ->runInBackground();
Метод runInBackground может быть только использован при планировании заданий через методы code>command и exec.

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

Запланированные задачи Ларавел не будут выполняться, если приложение находится в режиме обслуживания, в силу того, что мы не хотим, чтобы задания могли вступить в конфлик с незавершенной задачей на сервере. Однако, если вы хотите, можно запускать планировщик даже в режиме обслуживания. Для этого необходимо использовать метод evenInMaintenanceMode:

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

Вывод задач

Планировщик Ларавел предоставляет несколько удобных методов для работы с выводом, сгенерированным запланированными заданиями. Используя метод sendOutputTo вы можете отправить вывод на определённый файл для последующего прсмотра:

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

Если вы хотите дополнить дополнить вывод в данный файл, используйте метод appendOutputTo:

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

Используя метод emailOutputTo, вы можете выслать e-mail на определённый электронный почтовый ящик, на ваш выбор. Перед тем как высылать электронное письмо, необходимо настроить почтовый сервис Ларавел:

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

Если вы хотите отсылать электронное письмо только в том случае, когда команда провалится, используйте метод emailOutputOnFailure:

$schedule->command('foo')
         ->daily()
         ->emailOutputOnFailure('taylor@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...
         });

Пингование URL-адреса

Используя методы pingBefore и thenPing, планировщик может автоматичечки пинговать данный URL до или после выполнения задания. Этот метод полезен для информирования внешнего сервиса, такого как Laravel 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);

Методы pingOnSuccess и pingOnFailure могут быть использованы для того, чтобы пинговать данный URL, если задание выполнено соответсвенно успешно или закончилось неудачей:

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

Связанные с пингом методы требуют библиотеку HTTP Guzzle. Вы можете добавить Guzzle в ваше проект используя Composer:

composer require guzzlehttp/guzzle