Может войдёшь?
Черновики Написать статью Профиль

Планировщик задач

перевод документация 5.х

  1. 1. Введение
    1. 1.1. Запуск планировщика
  2. 2. Определение планировщика
    1. 2.1. Настройки частоты планировщика
    2. 2.2. Предотвращение перекрытий задач
    3. 2.3. Режим обслуживания
  3. 3. Выходные данные задачи
  4. 4. Обработчики прерываний задач
Этот перевод актуален для англоязычной документации на (ветка 5.3) , (ветка 5.2) и (ветка 5.1). Опечатка? Выдели и нажми Ctrl+Enter.

Введение

Раньше вы могли создавать 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
<?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-команду, используя либо имя команды, либо класс:

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

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

Команда PHPexec() может быть использована для обращения к операционной системе:

PHP
$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 и выше)

Эти методы могут быть объединены с дополнительными ограничениями для создания ещё более гибкого планировщика, который будет работать только в определённые дни недели. Например, чтобы запланировать команду на еженедельный запуск в понедельник:

PHP
// Запуск каждый понедельник в 13:00...
$schedule->call(function () {
  
//
})->weekly()->mondays()->at('13:00');
+ 5.3 5.2

добавлено в 5.3 () 5.2 ()

PHP
// Запускать каждый час с 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

добавлено в 5.3 ()

Ограничение промежутком времени

Методом PHPbetween() можно ограничить выполнение задачи в зависимости от времени дня:

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

А методом PHPunlessBetween() можно исключить выполнение задачи в указанный период времени:

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

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

Метод PHPwhen() может быть использован, чтобы ограничить выполнение задачи на основании результата успешно пройденного теста. Другими словами, если заданное PHPClosure возвращает true, задача будет выполняться до тех пор, пока никакие другие ограничивающие условия не препятствуют её выполнению:

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

добавлено в 5.2 ()

Метод PHPskip() является инверсией метода PHPwhen(). Если метод PHPskip() возвращает true, запланированная задача не будет запущена:

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

При использовании сцепленного метода PHPwhen(), запланированная команда выполнится только при условии, что все PHPwhen() возвратят true.

Предотвращение перекрытий задач

По умолчанию, запланированные задачи будут запускаться, даже если предыдущий экземпляр задачи всё ещё выполняется. Чтобы предотвратить это, вы можете использовать метод PHPwithoutOverlapping():

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

В этом примере Artisan-команда shemails:send будет запускаться каждую минуту, если она ещё не запущена. Метод PHPwithoutOverlapping() особенно полезен, если у вас есть задачи, которые изменяются коренным образом во время своего выполнения, что мешает вам предсказывать точно, сколько времени данная задача будет выполняться.

+ 5.3

добавлено в 5.3 ()

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

Запланированные задачи Laravel не будут запускаться, когда Laravel находится в режиме обслуживания, так как мы не хотим, чтобы ваши команды столкнулись с какими-либо незаконченными операциями обслуживания сервера. Но если вы хотите, чтобы задача запускалась даже в режиме обслуживания, вы можете использовать метод PHPevenInMaintenanceMode():

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

Выходные данные задачи

Планировщик Laravel предоставляет несколько удобных методов для работы с выходными данными, сгенерированными запланированными задачами. Во-первых, используя метод PHPsendOutputTo(), вы можете отправить вывод данных в файл для последующего анализа:

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

Если вы хотите добавить вывод в указанный файл, вы можете использовать метод PHPappendOutputTo():

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

Используя метод PHPemailOutputTo(), вы можете отправить по электронной почте выходные данные на адрес по вашему усмотрению. Обратите внимание, что данные должны быть сначала отправлены в файл с помощью метода PHPsendOutputTo(). Перед отправкой на электронную почту результата выполнения задачи вы должны настроить службы электронной почты Laravel:

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

Методы PHPemailOutputTo(), PHPsendOutputTo() и PHPappendOutputTo() доступны исключительно для метода PHPcommand() и не поддерживаются для PHPcall().

Обработчики прерываний задач

Используя методы PHPbefore() и PHPafter(), вы можете указать код, который будет выполняться до запуска и после завершения запланированной задачи:

PHP
$schedule->command('emails:send')
         ->
daily()
         ->
before(function () {
           
// Перед запуском задачи...
         
})
         ->
after(function () {
           
// Задача завершена...
         
});

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

Используя методы PHPpingBefore() и PHPthenPing(), планировщик может автоматически пинговать заданный URL до запуска и после завершения задачи. Этот метод полезен для уведомления внешней службы, например, Laravel Envoyer, о том, что ваша запланированная задача запустилась или закончила выполнение:

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

Использование функций PHPpingBefore($url) или PHPthenPing($url) требует библиотеки Guzzle HTTP.

+ 5.3

добавлено в 5.3 ()

Вы можете добавить Guzzle к вашему проекту с помощью менеджера пакетов Composer:

shcomposer require guzzlehttp/guzzle
+ 5.2 5.1

добавлено в 5.2 () 5.1 ()

Вы можете добавить Guzzle к вашему проекту, добавив следующую строку в файл composer.json:

"guzzlehttp/guzzle": "~5.3|~6.0"

Комментарии (8)

Sawa4

Всем привет! У вас заработал крон? Я делаю так:

*  *    * * *   root    /usr/bin/php /var/www/site.name/artisan schedule:run » /dev/null 2>&1

Но у меня не работает почему то на Debian 7.8, что я делаю не так?

Proger_XP

В статье >> стало кавычками, посмотри внимательно на свой код.

schedule:run » /dev
-------------^
Sawa4

это не то что я ищу, тут нарыл (точнее один умный человек сказал), что под рутом вообще нельзя ничего запускать никогда, так что в etc/crontab добавлять не вариант

Proger_XP

В crontab указывается пользователь (после звездочек), обычно это www-data, см. конфиг Apache/nginx/php, какой там пользователь.

Также можно использовать crontab -eu www-data для правки конфига пльзователья.

Sawa4

у меня Debian там пишу так /var/spool/cron/crontab/fileusername и тут без указание пользователя, проблема следующая, которая ниже в комменте

Sawa4

Вообщем понял одно Если писать просто $schedule->command('backup:run'); то пашет, а если $schedule->command('backup:run')->dailyAt('11:00'); или $schedule->command('backup:run')->daily()->at('11:00'); то не работает. Кто знает почему такое возможно?

Alexandr5

Для виндовса (например если тестирование на локалке на винде проходит)

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.

Взято отсюда

Artur9191

А задачи 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
}

Написать комментарий

Разметка: ? ?

Авторизуйся, чтобы прокомментировать.