Статьи

Как программировать с Yii2: запуск сервисов Cron

Конечный продукт
Что вы будете создавать

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

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

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

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

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

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use ‘*’ in these fields (for ‘any’).#
# Notice that tasks will be started based on the cron’s system
# daemon’s notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 am every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# mh dom mon dow command
*/3 * * * * wget -O /dev/null http://meetingplanner.io/daemon/frequent
*/15 * * * * wget -O /dev/null http://meetingplanner.io/daemon/quarter
0 * * * * wget -O /dev/null http://meetingplanner.io/daemon/hourly
15 1 * * * wget -O /dev/null http://meetingplanner.io/daemon/overnight
40 2 * * * /usr/sbin/automysqlbackup
15 3 * * 5 wget -O /dev/null http://meetingplanner.io/daemon/weekly
30 2 * * 1 /opt/letsencrypt/letsencrypt-auto renew >> /var/log/le-renew.log

В левой части указывается активация этих задач каждые 3 или 15 минут или ежедневно в полночь и т. Д., А в правой части — сценарий для запуска. См. Также Планирование задач с помощью Cron Jobs (Envato Tuts +) .

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
// only cron jobs and admins can run this controller’s actions
   public function beforeAction($action)
   {
     // your custom code here, if you want the code to run before action filters,
     // which are triggered on the [[EVENT_BEFORE_ACTION]] event, eg PageCache or AccessControl
     if (!parent::beforeAction($action)) {
         return false;
     }
     // other custom code here
     if (( $_SERVER[‘REMOTE_ADDR’] == $_SERVER[‘SERVER_ADDR’] ) ||
         (!\Yii::$app->user->isGuest && \common\models\User::findOne(Yii::$app->user->getId())->isAdmin()))
      {
        return true;
      }
     return false;
   }

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

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

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

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

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

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

Как программировать с помощью Yii2 - Cron на основе консоли - Twixxr Home Page Пример веб-сайта

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

Вот ядро ​​моего нового консольного DaemonController.php:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php
namespace console\controllers;
 
use Yii;
use yii\helpers\Url;
use yii\console\Controller;
use frontend\models\Twixxr;
 
/**
 * Test controller
 */
class DaemonController extends Controller {
 
    public function actionIndex() {
        echo «Yes, cron service is running.»;
    }
 
    public function actionFrequent() {
      // called every two minutes
      // */2 * * * * ~/sites/www/yii2/yii test
      $time_start = microtime(true);
      $x = new \frontend\models\Twixxr();
      $x->process($time_start);
      $time_end = microtime(true);
      echo ‘Processing for ‘.($time_end-$time_start).’
    }
 
    public function actionQuarter() {
        // called every fifteen minutes
        $x = new \frontend\models\Twixxr();
        $x->loadProfiles();
      }
 
      public function actionHourly() {
        // every hour
        $current_hour = date(‘G’);
        if ($current_hour%4) {
          // every four hours
        }
            if ($current_hour%6) {
            // every six hours
          }
        }

Обратите внимание, что он довольно идентичен структуре моего интерфейсного контроллера, но он безопасно недоступен для Интернета, потому что он находится в дереве / console. Ни один сайт веб-сервера Apache не настроен для просмотра этой области.

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

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

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

1
2
3
4
5
6
7
8
9
$ sudo crontab -l
# mh dom mon dow command
*/3 * * * * /var/www/twixxr/yii daemon/frequent
*/15 * * * * /var/www/twixxr/yii daemon/quarter
0 * * * * /var/www/twixxr/yii daemon/hourly
15 1 * * * /var/www/twixxr/yii daemon/overnight
15 3 * * 5 /var/www/twixxr/yii daemon/weekly
#40 2 * * * /usr/sbin/automysqlbackup
30 2 * * 1 /usr/bin/letsencrypt renew >> /var/log/le-renew.log

Это довольно просто. Левая часть /var/www/twixxr/yii daemon/frequent — это путь, по которому живет интерпретатор yii, а правая часть — контроллер консоли и вызываемый метод.

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

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

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

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

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

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