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

Если вы спрашиваете: «Что такое 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
и видите что-то вроде этого:
# 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 a.m 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) # # m h dom mon dow command */3 * * * * wget -O /dev/null https://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» (Envato Tuts +).
Обратите внимание, что скрипт Let's Encrypt является уникальной консольной командой. Он выполняется из командной строки на нашем сервере. Тем не менее все мои задачи Планировщика встреч, описанные выше, выполняются через wget. Это действует так, как если бы робот находился в веб-браузере в определенное время, выполняя запросы к нашему веб-приложению, для запуска фоновых задач.
Помимо накладных расходов, требуемых для внешнего веб-запроса, и ограничений времени на выполнение скриптов на серверах, вы должны обеспечить безопасность этих точек доступа. Вот пример того, как это делает Meeting Planner:
// 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, e.g. 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; // or false to not run the action }
Он проверяет, что пользователь либо зарегистрирован в качестве администратора, либо запущен локально на сервере с идентичным IP-адресом в Интернете.
Реализация консольных команд Cron
Алекс Макаров, один из ведущих волонтеров по разработке Yii Framework, помог мне ответить на вопросы, так как я регулярно пишу о фреймворке на Envato Tuts +. Прочитав мой эпизод обезопасности, он спросил, почему я не использую встроенную консольную возможность Yii2 для заданий cron. В принципе, я и не знал об этом.
Так же, как у меня был /frontend/controllers/DaemonController.php, я создал /console/controllers/DaemonController.php. Для этого урока я сделаю это для более мелкой и простой веб-службы Twixxr.
Я привык использовать консоль для запуска миграции баз данных (например, ./yii migrate / up 7
), но на этом все. Я очень хотел попробовать использовать ее для фоновых задач.
Как я писал в предыдущем уроке, мой новый сайт Twixxr требует обширных фоновых процессов, чтобы регулярно выполнять вызовы API для всех пользовательских запросов, чтобы подружить влиятельные учетные записи Twitter, которыми владеют женщины.
Вот как выглядит домашняя страница:

Поэтому я думал, что Twixxr станет отличным испытательным стендом для запуска консольного контроллера cron.
Новый DaemonController.php
Вот основа моего нового консольного DaemonController.php:
<?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).' seconds'; } 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 } }
Заметьте, что он очень похож на структуру моего front-end контроллера, но в целях безопасности он недоступен для Интернета, потому что находится в папке /console. Веб-сервер Apache не настроен для просмотра этой области.
Таким образом, в приведенном выше примере actionFrequent()
будет вызываться каждые две-три минуты. Он обрабатывает другой набор дружеских запросов Twixxr. С другой стороны, actionQuarter()
вызывается каждые 15 минут и обновляет информацию профиля для просмотра учетных записей. Давайте посмотрим, как работает планирование в файле cron.
Новый файл Crontab
По существу, в моем файле crontab я заменяю wget на прямой скрипт Linux, как показано выше для Let's Encrypt renewals.
Вы вводите sudo crontab -e
для редактирования или -l
для вывода его содержимого. Вот мой файл Twixxr cron:
$ sudo crontab -l # m h 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/frequently
- это путь, по которому находится интерпретатор yii, а правая часть - консольный контроллер и его метод.
Все работало очень хорошо. Я еще не перешел на Планировщика встреч, так как хочу провести дополнительное тестирование. Когда фоновые задачи прерываются, трудно узнать и сложно отладить их (хотя регистрация ошибок Sentry очень помогает).
Вопросы для рассмотрения
Один элемент, с которым я столкнулся, состоит в том, что пространство имен консоли отличается от пространства имен front-end - так, например, компонент SiteHelper.php, который я создал в своем учебнике, в котором описан запуск нескольких сайтов из одной кодовой базы, завершился неудачно, когда я вызывал его. Удаление его сработало, но мне нужно было запустить тесты, чтобы убедиться, что основной фоновый код все еще функционирует. Однако, в основном, переход прошел гладко.
Как и в случае с любым другим изменением кода, тщательно протестируйте и проведите мониторинг.
Что дальше
Заглядывая в будущее, я исследую создание API REST в рамках Yii2 Framework, которое полагается расположить в отдельном поддереве, по аналогии с консолью, но для внешних API. Конечно, это потребует сложной аутентификации и проблемы безопасности ... так что будет интересно исследовать их вместе с вами. Я буду рассматривать API с нескольких точек зрения. Мне действительно это очень интересно.
Следите за предстоящими учебниками в моей серии по программированию с помощью Yii2, поскольку я продолжаю погружаться в различные аспекты фреймворка. Просьба также ознакомиться со статьей «Создание стартапа на PHP», в котором описывается процесс создания Simple Planner и Meeting Planner.
Если вы хотите знать, когда выйдет следующий учебник Yii2, подпишитесь на меня @reifman в Twitter или проверьте мою страницу инструктора для получения последних обновлений.
Ссылки по теме
- Yii2 Developer Exchange, мой ресурсный сайт Yii2
- Планирование задач с помощью заданий Cron (Envato Tuts +)
- Как реализовать cron в Yii2 (Yii Документация)
- Twixxr, пример веб-сервиса, упомянутый выше
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post