1. Code
  2. Coding Fundamentals
  3. Terminal and CLI

Учимся программировать с Yii2: Запуск cron команд

Если вы спрашиваете: «Что такое Yii?» Ознакомьтесь с моим предыдущим руководством: Знакомство с Yii Framework, в котором рассмотрены преимущества Yii и представлен обзор того, что было представлено нового в Yii 2.0, в октябре 2014 года.
Scroll to top
This post is part of a series called How to Program With Yii2.
How to Program With Yii2: ActiveRecord
Programming With Yii2: Building a RESTful API

Russian (Pусский) translation by Ilya Nikov (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

Если вы спрашиваете: «Что такое Yii?» Ознакомьтесь с моим предыдущим руководством: Знакомство с Yii Framework, в котором рассмотрены преимущества Yii и представлен обзор того, что было представлено нового в Yii 2.0, в октябре 2014 года.

В этой программирование с Yii2 я учу своих читателей  использовать Yii2 Framework для PHP. В сегодняшнем руководстве я расскажу вам, как использовать возможности консоли Yii для запуска заданий cron.

Раньше я использовал wget в своих заданиях cron - веб-доступный URL-адрес запускал мои фоновые задачи. Что вызвало проблемы с безопасностью и некоторые проблемы с производительностью. В то время как я рассматривал некоторые способы снижения рисков в эпизодах серии новичок в безопасности, я надеялся перейти к консольным командам. И с Yii2 это стало довольно просто.

На сегодняшнем примере я продемонстрирую консольные команды cron на своем сайте Twixxr, которые я описывал в этом эпизоде API Twitter. Из-за ограничений скорости и управления производительностью API Twitter очень зависит от эффективных и надежных cron задач. Так что это отличный пример, чтобы поделиться им с вами.

Прежде чем начать, я еще раз повторюсь: я всегда благодарен за ваши идеи и отзывы. Если у вас есть вопрос или предложение, оставляйте свои мысли в комментарии ниже. Вы также можете связаться со мной прямо в Twitter @reifman.

Что такое Cron?

Википедия описывает cron как «планировщик заданий по времени в Unix-подобных компьютерных операционных системах». И это описание довольно точное. В основном, cron запускает все фоновые задачи, которые нам нужны для запуска веб-служб, от управления журналом и резервного копирования до запросов API для очстки базы данных.

Чтобы увидеть существующие задания cron на сервере, вы обычно набираете sudo crontab -l и видите что-то вроде этого:

1
# Edit this file to introduce tasks to be run by cron.

2
# 

3
# Each task to run has to be defined through a single line

4
# indicating with different fields when the task will be run

5
# and what command to run for the task

6
# 

7
# To define the time you can provide concrete values for

8
# minute (m), hour (h), day of month (dom), month (mon),

9
# and day of week (dow) or use '*' in these fields (for 'any').# 

10
# Notice that tasks will be started based on the cron's system

11
# daemon's notion of time and timezones.

12
# 

13
# Output of the crontab jobs (including errors) is sent through

14
# email to the user the crontab file belongs to (unless redirected).

15
# 

16
# For example, you can run a backup of all your user accounts

17
# at 5 a.m every week with:

18
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/

19
# 

20
# For more information see the manual pages of crontab(5) and cron(8)

21
# 

22
# m h  dom mon dow   command

23
*/3 * * * * wget -O /dev/null https://meetingplanner.io/daemon/frequent
24
*/15 * * * * wget -O /dev/null http://meetingplanner.io/daemon/quarter
25
0 * * * * wget -O /dev/null http://meetingplanner.io/daemon/hourly
26
15 1 * * * wget -O /dev/null http://meetingplanner.io/daemon/overnight
27
40 2 * * * /usr/sbin/automysqlbackup
28
15 3 * * 5 wget -O /dev/null http://meetingplanner.io/daemon/weekly
29
30 2 * * 1 /opt/letsencrypt/letsencrypt-auto renew >> /var/log/le-renew.log

Левая сторона указывает активировать эти задачи каждые 3 или 15 минут или ежедневно в полночь и т.д., А правая часть - это сценарий для запуска. Смотрите также «Планирование заданий с командами Cron» (Envato Tuts +).

Обратите внимание, что скрипт Let's Encrypt является уникальной консольной командой. Он выполняется из командной строки на нашем сервере. Тем не менее все мои задачи Планировщика встреч, описанные выше, выполняются через wget. Это действует так, как если бы робот находился в веб-браузере в определенное время, выполняя запросы к нашему веб-приложению, для запуска фоновых задач.

Помимо накладных расходов, требуемых для внешнего веб-запроса, и ограничений времени на выполнение скриптов на серверах, вы должны обеспечить безопасность этих точек доступа. Вот пример того, как это делает Meeting Planner:

1
// only cron jobs and admins can run this controller's actions

2
    public function beforeAction($action)
3
    {
4
      // your custom code here, if you want the code to run before action filters,

5
      // which are triggered on the [[EVENT_BEFORE_ACTION]] event, e.g. PageCache or AccessControl

6
      if (!parent::beforeAction($action)) {
7
          return false;
8
      }
9
      // other custom code here

10
      if (( $_SERVER['REMOTE_ADDR'] == $_SERVER['SERVER_ADDR'] ) ||
11
          (!\Yii::$app->user->isGuest && \common\models\User::findOne(Yii::$app->user->getId())->isAdmin()))
12
       {
13
         return true;
14
       }
15
      return false; // or false to not run the action

16
    }

Он проверяет, что пользователь либо зарегистрирован в качестве администратора, либо запущен локально на сервере с идентичным IP-адресом в Интернете.

Реализация консольных команд Cron

Алекс Макаров, один из ведущих волонтеров по разработке Yii Framework, помог мне ответить на вопросы, так как я регулярно пишу о фреймворке на Envato Tuts +. Прочитав мой эпизод обезопасности, он спросил, почему я не использую встроенную консольную возможность Yii2 для заданий cron.  В принципе, я и не знал об этом.

Так же, как у меня был /frontend/controllers/DaemonController.php, я создал /console/controllers/DaemonController.php. Для этого урока я сделаю это для более мелкой и простой веб-службы Twixxr.

Я привык использовать консоль для запуска миграции баз данных (например, ./yii migrate / up 7), но на этом все. Я очень хотел попробовать использовать ее для фоновых задач.

Как я писал в предыдущем уроке, мой новый сайт Twixxr требует обширных фоновых процессов, чтобы регулярно выполнять вызовы API для всех пользовательских запросов, чтобы подружить влиятельные учетные записи Twitter, которыми владеют женщины.

Вот как выглядит домашняя страница:

How to Program with Yii2 - Console-Based Cron - Twixxr Home Page Example WebsiteHow to Program with Yii2 - Console-Based Cron - Twixxr Home Page Example WebsiteHow to Program with Yii2 - Console-Based Cron - Twixxr Home Page Example Website

Поэтому я думал, что Twixxr станет отличным испытательным стендом для запуска консольного контроллера cron.

Новый DaemonController.php

Вот основа моего нового консольного DaemonController.php:

1
<?php
2
namespace console\controllers;
3
4
use Yii;
5
use yii\helpers\Url;
6
use yii\console\Controller;
7
use frontend\models\Twixxr;
8
9
/**

10
 * Test controller

11
 */
12
class DaemonController extends Controller {
13
14
    public function actionIndex() {
15
        echo "Yes, cron service is running.";
16
    }
17
18
    public function actionFrequent() {
19
      // called every two minutes

20
      // */2 * * * * ~/sites/www/yii2/yii test

21
      $time_start = microtime(true);
22
      $x = new \frontend\models\Twixxr();
23
      $x->process($time_start);
24
      $time_end = microtime(true);
25
      echo 'Processing for '.($time_end-$time_start).' seconds';
26
    }
27
28
    public function actionQuarter() {
29
        // called every fifteen minutes

30
        $x = new \frontend\models\Twixxr();
31
        $x->loadProfiles();
32
      }
33
34
      public function actionHourly() {
35
        // every hour

36
        $current_hour = date('G');
37
        if ($current_hour%4) {
38
          // every four hours

39
        }
40
            if ($current_hour%6) {
41
            // every six hours

42
          }
43
        }

Заметьте, что он очень похож на структуру моего front-end контроллера, но в целях безопасности он недоступен для Интернета, потому что находится в папке /console. Веб-сервер Apache не настроен для просмотра этой области.

Таким образом, в приведенном выше примере actionFrequent() будет вызываться каждые две-три минуты. Он обрабатывает другой набор дружеских запросов Twixxr. С другой стороны, actionQuarter() вызывается каждые 15 минут и обновляет информацию профиля для просмотра учетных записей. Давайте посмотрим, как работает планирование в файле cron.

Новый файл Crontab

По существу, в моем файле crontab я заменяю wget на прямой скрипт Linux, как показано выше для Let's Encrypt renewals.

Вы вводите sudo crontab -e для редактирования или -l для вывода его содержимого. Вот мой файл Twixxr cron:

1
$ sudo crontab -l
2
# m h  dom mon dow   command

3
*/3 * * * * /var/www/twixxr/yii daemon/frequent
4
*/15 * * * * /var/www/twixxr/yii daemon/quarter
5
0 * * * * /var/www/twixxr/yii daemon/hourly
6
15 1 * * * /var/www/twixxr/yii daemon/overnight
7
15 3 * * 5 /var/www/twixxr/yii daemon/weekly
8
#40 2 * * * /usr/sbin/automysqlbackup

9
30 2 * * 1 /usr/bin/letsencrypt renew >> /var/log/le-renew.log

Все довольно просто. Левая сторона /var/www/twixxr/yii daemon/frequently - это путь, по которому находится интерпретатор yii, а правая часть - консольный контроллер и его метод.

Все работало очень хорошо. Я еще не перешел на Планировщика встреч, так как хочу провести дополнительное тестирование. Когда фоновые задачи прерываются, трудно узнать и сложно отладить их (хотя регистрация ошибок Sentry очень помогает).

Вопросы для рассмотрения

Один элемент, с которым я столкнулся, состоит в том, что пространство имен консоли отличается от пространства имен front-end - так, например, компонент SiteHelper.php, который я создал в своем учебнике, в котором описан запуск нескольких сайтов из одной кодовой базы, завершился неудачно, когда я вызывал его. Удаление его сработало, но мне нужно было запустить тесты, чтобы убедиться, что основной фоновый код все еще функционирует. Однако, в основном, переход прошел гладко.

Как и в случае с любым другим изменением кода, тщательно протестируйте и проведите мониторинг.

Что дальше

Заглядывая в будущее, я исследую создание API REST в рамках Yii2 Framework, которое полагается расположить в отдельном поддереве, по аналогии с консолью, но для внешних API. Конечно, это потребует сложной аутентификации и проблемы безопасности ... так что будет интересно исследовать их вместе с вами. Я буду рассматривать API с нескольких точек зрения. Мне действительно это очень интересно.

Следите за предстоящими учебниками в моей серии по программированию с помощью Yii2, поскольку я продолжаю погружаться в различные аспекты фреймворка. Просьба также ознакомиться со статьей «Создание стартапа на PHP», в котором описывается процесс создания Simple Planner и Meeting Planner.

Если вы хотите знать, когда выйдет следующий учебник Yii2, подпишитесь на меня @reifman в Twitter или проверьте мою страницу инструктора для получения последних обновлений.

Ссылки по теме