Введение
Раньше вы могли создавать Cron-записи для каждой запланированной задачи на вашем сервере. Но это могло быстро превратиться в рутину, так как планировщик задач больше не находится в системе контроля версий, и вы должны заходить через SSH на свой сервер, чтобы добавить Cron-записи.
Планировщик команд Laravel позволяет вам гибко и выразительно определить планирование своих команд в самом Laravel. И для этого на вашем сервере необходима только одна Cron-запись. Ваш планировщик задач определён в методе PHPschedule()
файла app/Console/Kernel.php. Чтобы помочь вам начать, там уже есть простой пример с методом.
Запуск планировщика
При использовании планировщика вам надо добавить на ваш сервер только одну эту Cron-запись. Если вы не знаете, как добавлять Cron-записи на сервер, то можете использовать такой сервис, как Laravel Forge, который может управлять Cron-записями для вас:
sh* * * * * php /path/to/artisan schedule:run >>/dev/null 2>&1
Этот Cron будет вызывать планировщик команд Laravel каждую минуту. Когда будет выполнена команда shschedule:run
, Laravel обработает ваши запланированные задачи и запустит только те задачи, которые должен.
Определение планировщика
Вы можете определить все свои запланированные задачи в методе PHPschedule()
класса App\Console\Kernel. Для начала давайте посмотрим на пример планирования задачи. В этом примере мы запланируем замыкание PHPClosure
, которое будет вызываться каждый день в полночь. В PHPClosure
мы выполним запрос БД, чтобы очистить таблицу:
<?php
namespace App\Console;
use DB;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* Artisan-команды вашего приложения.
*
* @var array
*/
protected $commands = [
\App\Console\Commands\Inspire::class,
];
/**
* Определяем планировщик команд приложения.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->call(function () {
DB::table('recent_users')->delete();
})->daily();
}
}
В дополнение к планированию вызовов PHPClosure
вы можете также запланировать Artisan-команды и команды операционной системы. Например, вы можете использовать метод PHPcommand()
, чтобы запланировать Artisan-команду, используя либо имя команды, либо класс:
$schedule->command('emails:send —force')->daily();
$schedule->command(EmailsCommand::class, ['--force'])->daily();
Команда PHPexec()
может быть использована для обращения к операционной системе:
$schedule->exec('node /home/forge/script.js')->daily();
Настройки частоты планировщика
Конечно, есть множество вариантов планировщика, которые вы можете назначить на свою задачу:
Метод | Описание |
---|---|
->cron('* * * * *'); | Запускать задачу по пользовательскому расписанию |
->everyMinute(); | Запускать задачу каждую минуту |
->everyFiveMinutes(); | Запускать задачу каждые 5 минут |
->everyTenMinutes(); | Запускать задачу каждые 10 минут |
->everyThirtyMinutes(); | Запускать задачу каждые 30 минут |
->hourly(); | Запускать задачу каждый час |
->hourlyAt(17); | Запускать задачу каждый час в хх:17 минут (для версии 5.3 и выше) |
->daily(); | Запускать задачу каждый день в полночь |
->dailyAt('13:00'); | Запускать задачу каждый день в 13:00 |
->twiceDaily(1, 13); | Запускать задачу каждый день в 1:00 и 13:00 |
->weekly(); | Запускать задачу каждую неделю |
->monthly(); | Запускать задачу каждый месяц |
->monthlyOn(4, '15:00'); | Запускать задачу 4 числа каждого месяца в 15:00 (для версии 5.2 и выше) |
->quarterly(); | Запускать задачу каждые 3 месяца (для версии 5.2 и выше) |
->yearly(); | Запускать задачу каждый год |
->timezone('America/New_York'); | Задать часовой пояс (для версии 5.2 и выше) |
Эти методы могут быть объединены с дополнительными ограничениями для создания ещё более гибкого планировщика, который будет работать только в определённые дни недели. Например, чтобы запланировать команду на еженедельный запуск в понедельник:
// Запуск каждый понедельник в 13:00...
$schedule->call(function () {
//
})->weekly()->mondays()->at('13:00');
// Запускать каждый час с 8:00 до 17:00 по будням...
$schedule->command('foo')
->weekdays()
->hourly()
->timezone('America/Chicago')
->between('8:00', '17:00');
Ниже приведён список дополнительных ограничений в расписании:
Метод | Описание |
---|---|
->weekdays(); | Ограничить задачу рабочими днями |
->sundays(); | Ограничить задачу воскресеньем |
->mondays(); | Ограничить задачу понедельником |
->tuesdays(); | Ограничить задачу вторником |
->wednesdays(); | Ограничить задачу средой |
->thursdays(); | Ограничить задачу четвергом |
->fridays(); | Ограничить задачу пятницей |
->saturdays(); | Ограничить задачу субботой |
->between($start, $end); | Ограничить запуск задачи между временем начала и конца промежутка (для версии 5.3 и выше) |
->when(Closure); | Ограничить задачу на основе успешного теста |
добавлено в 5.3 ()
Ограничение промежутком времени
Методом PHPbetween()
можно ограничить выполнение задачи в зависимости от времени дня:
$schedule->command('reminders:send')
->hourly()
->between('7:00', '22:00');
А методом PHPunlessBetween()
можно исключить выполнение задачи в указанный период времени:
$schedule->command('reminders:send')
->hourly()
->unlessBetween('23:00', '4:00');
Метод PHPwhen()
может быть использован, чтобы ограничить выполнение задачи на основании результата успешно пройденного теста. Другими словами, если заданное PHPClosure
возвращает true, задача будет выполняться до тех пор, пока никакие другие ограничивающие условия не препятствуют её выполнению:
$schedule->command('emails:send')->daily()->when(function () {
return true;
});
добавлено в 5.2 ()
При использовании сцепленного метода PHPwhen()
, запланированная команда выполнится только при условии, что все PHPwhen()
возвратят true.
Предотвращение перекрытий задач
По умолчанию, запланированные задачи будут запускаться, даже если предыдущий экземпляр задачи всё ещё выполняется. Чтобы предотвратить это, вы можете использовать метод PHPwithoutOverlapping()
:
$schedule->command('emails:send')->withoutOverlapping();
В этом примере Artisan-команда shemails:send
будет запускаться каждую минуту, если она ещё не запущена. Метод PHPwithoutOverlapping()
особенно полезен, если у вас есть задачи, которые изменяются коренным образом во время своего выполнения, что мешает вам предсказывать точно, сколько времени данная задача будет выполняться.
добавлено в 5.3 ()
Режим обслуживания
Запланированные задачи Laravel не будут запускаться, когда Laravel находится в режиме обслуживания, так как мы не хотим, чтобы ваши команды столкнулись с какими-либо незаконченными операциями обслуживания сервера. Но если вы хотите, чтобы задача запускалась даже в режиме обслуживания, вы можете использовать метод PHPevenInMaintenanceMode()
:
$schedule->command('emails:send')->evenInMaintenanceMode();
Выходные данные задачи
Планировщик Laravel предоставляет несколько удобных методов для работы с выходными данными, сгенерированными запланированными задачами. Во-первых, используя метод PHPsendOutputTo()
, вы можете отправить вывод данных в файл для последующего анализа:
$schedule->command('emails:send')
->daily()
->sendOutputTo($filePath);
Если вы хотите добавить вывод в указанный файл, вы можете использовать метод PHPappendOutputTo()
:
$schedule->command('emails:send')
->daily()
->appendOutputTo($filePath);
Используя метод PHPemailOutputTo()
, вы можете отправить по электронной почте выходные данные на адрес по вашему усмотрению. Обратите внимание, что данные должны быть сначала отправлены в файл с помощью метода PHPsendOutputTo()
. Перед отправкой на электронную почту результата выполнения задачи вы должны настроить службы электронной почты Laravel:
$schedule->command('foo')
->daily()
->sendOutputTo($filePath)
->emailOutputTo('foo@example.com');
Методы PHPemailOutputTo()
, PHPsendOutputTo()
и PHPappendOutputTo()
доступны исключительно для метода PHPcommand()
и не поддерживаются для PHPcall()
.
Обработчики прерываний задач
Используя методы PHPbefore()
и PHPafter()
, вы можете указать код, который будет выполняться до запуска и после завершения запланированной задачи:
$schedule->command('emails:send')
->daily()
->before(function () {
// Перед запуском задачи...
})
->after(function () {
// Задача завершена...
});
Используя методы PHPpingBefore()
и PHPthenPing()
, планировщик может автоматически пинговать заданный URL до запуска и после завершения задачи. Этот метод полезен для уведомления внешней службы, например, Laravel Envoyer, о том, что ваша запланированная задача запустилась или закончила выполнение:
$schedule->command('emails:send')
->daily()
->pingBefore($url)
->thenPing($url);
Использование функций PHPpingBefore($url)
или PHPthenPing($url)
требует библиотеки Guzzle HTTP.
добавлено в 5.3 ()
Комментарии (10)
Всем привет! У вас заработал крон? Я делаю так:
Но у меня не работает почему то на Debian 7.8, что я делаю не так?
В статье >> стало кавычками, посмотри внимательно на свой код.
это не то что я ищу, тут нарыл (точнее один умный человек сказал), что под рутом вообще нельзя ничего запускать никогда, так что в etc/crontab добавлять не вариант
В crontab указывается пользователь (после звездочек), обычно это www-data, см. конфиг Apache/nginx/php, какой там пользователь.
Также можно использовать
crontab -eu www-data
для правки конфига пльзователья.у меня Debian там пишу так /var/spool/cron/crontab/fileusername и тут без указание пользователя, проблема следующая, которая ниже в комменте
Вообщем понял одно Если писать просто
$schedule->command('backup:run');
то пашет, а если$schedule->command('backup:run')->dailyAt('11:00');
или$schedule->command('backup:run')->daily()->at('11:00');
то не работает. Кто знает почему такое возможно?Для виндовса (например если тестирование на локалке на винде проходит)
This is possible with Windows Task Scheduler but the downside is the lowest it can be set to is Every 5 Minutes which is still ok for a testing environment.
I created a batch file scheduler.bat with the following contents
PHPcd c:\lamp\www\cw5
PHPC:\lamp\bin\php\php-5.6.3\php.exe artisan schedule:run 1>> NUL 2>&1
.Change directorys to match your setup. My project root is cw5
If you have php successfully added to your PATH variable then the second line can read php artisan..... no need for an exact location. But you will need to make sure you cd to your project root first.
Then launch the task scheduler Windows Key + R then paste in Taskschd.msc and hit enter.
Then click Create Basic Task on the right in the Actions pane.
Name your task something so you will know what it is for if you need to modify it or are running multiple projects then click Next.
Leave this page set to Daily for now and click Next.
Leave this page as defaults as well and click Next.
Make sure Start a Program is selected and click Next.
Browse to the batch file we just created and then click Next then click Finish.
Now, select Task Scheduler Library on the left, and find your task in the middle pane and right-click and click Properties
Go to the Triggers tab, click Daily in the list and click Edit.
The drop-down at the top next to Begin the task change to At Log on for Any user
Check the box that says Repeat Task Every and choose 5 Minutes from the drop-down. The drop-down after for a duration: on the same line choose Indefinitely.
Click OK. Done.
Then right-click on your task in the middle pane and click Run to initiate it.
Взято отсюда
А задачи 1, 2 и т.д. будут выполняться синхронно или асинхронно?
Задача 1 дожидается выполнения задачи 2?
$schedule->command('emails:send —force')->->everyMinute(); //задача 1
$schedule->command('phone:send —force')->->everyMinute(); //задача 2
foreach($drivers as $driver) {
$schedule->command('driver:fire —driverId=' . $driver->id)->->everyMinute(); //команда n+2
}
на крон выдет ошибку
Undefined variable: boundary
запускаю очистку кеша php artisan cache:clear
[ErrorException]
Undefined variable: boundary
эта проблема решена — теперь
Running scheduled command: Closure
[Symfony\Component\Debug\Exception\FatalThrowableError]
Class 'App\Task' not found