Работа с CRON и с консолью - energy-coresky/air GitHub Wiki
Задачи cron обычно находятся в main/cron.php, файл запускается раз в минуту, но время выполнения каждой задачи указывается непосредственно перед лямбда-функцией с помощью cron-синтаксиса. Задачи выполняются в отдельных потоках, возможно параллельно несколько сразу (обеспечивается с помощью функции PHP popen(..)
), поэтому даже фатальные ошибки отдельной задачи не нарушают работу остальных задач и регистрируются в системе регистрации ошибок. Функционал реализован в классе Schedule см. файл main/w2/schedule.php. Пример файла cron.php:
<?php
define('START_TS', microtime(true));
#'cli' == PHP_SAPI or exit;
$argv[0] = __FILE__;
require __DIR__ . '/../bootstrap.php';
$sky = new SKY;
$cron = new Schedule;
$cron
->at('0 2,3', fn() => $cron->visitors()) # run task at 2:00 and 3:00 every night
->at('30 5', fn() => $cron->mail_error())
->at('3', false, fn() => new This_task_dont_load_database) # second param is false
->turn(fn() => false)
->at('+', function() {
# this task never run due to "turn/false"
})
->turn(fn() => true)
->at('+', function() {
# this task run every times
})
->at('named', fn() => new Task)
# .. other tasks
?>
В консольных скриптах для создания центрального объекта, всегда используется класс SKY, в отличие от веб скриптов, где всегда используется класс HEAVEN, расширяющий класс SKY.
В задачах вместо глобальной функции sql()
, можно использовать $cron->sql()
, используя тот-же синтаксис, но вторая еще логирует свое исполнение в Cron-логе, например:
2018-05-01 00:02:01 [0] 0.001 sec <= 2423 <= delete from visitors where ...
Также, чтобы записать произвольную строку в лог, можно использовать $cron->write(..)
или echo
. Вне cron-скриптов, запись в Cron Log, всегда можно выполнить так: SKY::log('log some info')
.
С помощью функции $cron->mail_error()
можно организовать задачу отсылки письма, если на продакшн, появились новые ошибки и они не просмотрены в логе ошибок.
Первым параметром Schedule::at(..)
, вместо Cron-расписания, можно указать имя расписания, которое должно начинаться с латинской буквы, смотрите крайнюю задачу выше. В этом случае, расписание будет располагаться в файле main/cron.times в формате "Bang", который можно редактировать из Root-Admin раздела, т.е. изменять расписание на продакшн из веб-интерфейса. Если имя расписания в этом файле не найдено, первоначально будет назначено '-' - отключенная задача. Для именованных задач, в Cron-логе, автоматически указывается имя, кроме номера задачи в цепочке лямбда функций.
Если задача нормально выполнилась и не сделала запись в лог, также как и не сделала echo, она не будет отмечена ни в каких логах. Хотя любая крайняя задача, которая нормально выполнилась всегда отображается на вкладке Main/Overview в строке "Cron layer last tick". Это не касается только задач, которые выполнились не создавая соединение с базой данных. Если нужно, чтобы выполнение Cron-задачи отмечалось в логе, сделайте в теле задачи хотя-бы echo '-';
.
Запуск CRON-задач
Стандартная строка запуска в crontab:
* * * * * php /path-to-project/main/cron.php @ 2>&1
Здесь амперсанд перенаправляет весь вывод из stdout в крон лог. Во время разработки, задачи можно запускать так: php cron.php
, в этом случае, весь вывод в stdout и stderror будет в консоле.
Для того, чтобы задача гарантированно запустилась при любом вызове php cron.php
, необходимо первым символом расписания, указать + (плюс). Чтобы полностью отключить задачу (но при этом не затереть ее расписание), можно первым символом указать - (минус).
Для имитации использования Unix утилиты flock, можно первым символом расписания указать ! (восклицательный знак). Такие запущенные задачи, записывают файл с временем запуска var/cron/task_N (N - цифра, номер задачи в цепочке лямбда функций) и после окончания выполнения удаляют его.
Cron для Windows
Можно настроить планировщик задач Windows, чтобы он работал подобно программе Cron Unix систем. Чтобы запуск происходил в фоновом режиме, настройте планировщик Windows для запуска файла Visual Basic:
Dim WinScriptHost
Set WinScriptHost = CreateObject("WScript.Shell")
WinScriptHost.Run Chr(34) & "C:\path-to-file\cron.bat" & Chr(34), 0
Set WinScriptHost = Nothing
При этом файл cron.bat примерно такой:
php -f C:\path-to-sky-project\cron.php @ 2>&1
Или с помощью Visual Basic запустить бесконечный цикл PHP в фоне:
<?php
loop:
if (time() % 300 < 10) {
exec('php -f C:\path-to-sky-project\cron.php @ 2>&1');
sleep(11);
}
sleep(1);
goto loop;
Выполнение задач в едином потоке
Иногда функция PHP popen()
может быть отключена по соображениям безопасности у некоторых хостинг провайдеров. В этом случае выполнение задач будет происходить последовательно в одном процессе PHP (для задач, запуск который совпал на одно и то-же время).
Задать выполнение задач в одном процессе, можно также в конструкторе класса Schedule, хотя это не очень хорошая идея - предпочтительно использовать возможности popen()
.
Организовать выполнение задач в одном потоке можно также с помощью HTTP запросов:
* * * * * curl http://example.net/proxy.php
Где файл proxy.php выглядит примерно так:
<?php
'ip_addr' == $_SERVER["REMOTE_ADDR"] or exit; # где ip_addr - ip адрес сервера
require '../main/cron.php';
Методы для организации цепочки задач
Единственный метод для определения задач - ->at(..)
. Первый параметр - расписание. Второй параметр, если false - доступ к БД не инициируется, если true или второй параметр Closure - доступ к БД инициируется и задача может использовать главное соединение к БД. Ежеминутный запуск файла cron.php, сам по себе, также не инициирует доступ к базам данных. Внутри последнего параметра, Closure, описывается код задачи. Можно в параметре лямбда функции указать переменную, которая будет содержать номер задачи в цепочке (нумерация начинается с нуля). Расписание задачи может содержать имя расписания, читайте об этом выше.
Второй метод, который может участвовать в построении цепочки задач - ->turn()
. Если в этом методе (его лямбда функции) вернуть false, то все задачи после него в цепочке не будут выполняться. Однако можно указать второй ->turn()
, который разрешит (если вернет true) выполнение задач в дальнейшей цепочке.
Конфигурационные переменные класса Schedule
Класс Schedule имеет собственный реестр переменных, который организован с помощью ghost SQL. Значения сохраняются в memory.9 (стандартная таблица memory, ряд с ID равный 9). Переменные можно посмотреть в консоли sky m 9
или изменить: sky eval "SKY::n('clear_nc', null);"
. Для доступа к переменным, нужно использовать префикс n_, объект - $cron
или $sky
:
$cron->n_some_var = 'test'; # write var to database
echo $sky->n_some_var; # read var from database
sky
Класс Console и скрипт В CORESKY имеется консольный скрипт sky и "батник" для Windows sky.bat. В классе Console имплементировано для него несколько базовых команд:
>sky
Usage: sky command [param ...]
Commands are:
a Show top-view actions (routes)
acl List `acl` commands
app List `app` commands
c Show controllers
css Parse CSS file
d List dirs (from current dir)
drop Drop all cache
e Search for errors using all possible methods
eval Eval PHP code, example: sky eval "echo $sky->s_online;"
fr Write "first run" into index.php
g Check globals
gate Write default gate.php
m Read tmemo cell from $_memory
master Push repository to remote origin master
php Lint PHP files (from current dir)
rewrite Write default rewrite.php
s Run PHP web-server
sql Execute SQL, example: sky sql "+select 1+1" [con-name] [ware]
t Show tables [ware=main] [con-name]
ts Show table structure [tbl-name] [ware-main] [con-name]
v Show Coresky version
venus List `venus` commands
w List installed wares
warm Warm all cache
x Parse XML file
y Parse YML [ware=main] [fn=config.yaml] [one of 0|1|2] or Inline Yaml > sky y "+ @csv(;) $PATH()"
z Show ZML file info (.zml or .sky file extension)
Coresky app: ἄλφα.0.5145.HOLE.SKY. (hole.sky)
Repository: https://github.com/energy-coresky/empty-app.git
SKY-приложения могут расширить список этих команд в классе с фиксированным именем App
, main/w3/app.php. Пример класса App:
<?php
class App extends Console
{
/** This is just test */
function a_test() {
var_dump(SKY::$dd);
}
/** Test without DB */
function a__test() {
var_dump(SKY::$dd);
}
}
Методы для команд начинаются с "a_", а в DOC-comment блоке можно описать назначение команд. Если описание сделано, такие команды будут представлены во время вывода "USAGE". Командам приложений предшествует "app", например: sky app test
. Если команда начинается с подчеркивания, автоматическое подключение к базе данных не будет выполнено: sky app _test
.
Продукты также могут содержать расширения для скрипта sky
, аналогичные классам App
приложений. Для этого нужно создать аналогичный файл в папке w3 и использовать namespace соответствующий имени продукта:
<?php
namespace venus;
use Plan, Maat, Vesper, Maxwell;
class app extends \Console
{
function __construct($argv = [], $found = []) {
Plan::set('venus', fn() => parent::__construct($argv, $found));
}
/** Parse css */
function a_parse() { # "sky venus parse"
new Maat;
}
}
Если в переменную окружения PATH внести путь к скрипту sky
, то его можно будет запускать с любого места в файловой системе. При этом, скрипт может находить SKY-приложения, SKY-продукты и просто репозитории git, двигаясь вверх по иерархии папок. Для SKY-приложений, список команд наиболее широкий. При установке продуктов из инструментов разработчика, система записывает файл .coresky, содержащий путь к приложению. Таким образом, консольные команды приложений, можно выполнять в том числе из директорий продуктов.
Master
в приложениях
Класс Если приложение связано с продуктом посредством файла .coresky, то в приложении возможно создать класс Master
в файле main/w3/master.php, который будет задействован во время push продуктов. Когда выполняется git push..
в удаленный репозиторий, с помощью команды sky master
для продуктов, то будет выполнен код: new Master(self::$d[1]);
в приложении, смотрите код метода Console::master(..)
в файле w2/console.php. В конструктор класса Master
передается путь к продукту. Это дает возможность, например, логировать push-ы разрабатываемых продуктов в приложении или совершать другие необходимые действия.
First-Run
page
Скрипт Для тестирования окружения на новых инсталляциях SKY-приложений, Coresky умеет автоматически генерировать скрипт "First-Run" page, вместо public/index.php.
Для генерации этого скрипта с целью тестирования, можно запустить в консоле sky fr
.
При запуске sky master
(только для SKY-приложений, но не wares), перед коммитом и пушем в удаленный репозиторий, эта команда вызывает common_c::make_h(true);
и также common_c::make_h(false);
в конце обработки. Если этот метод трейта HOOK_C
не переопределен, то будет происходить стандартная обработка: вызывается метод Install::make($forward = true, Array $plus = [])
. Когда $forward = true
- public/index.php заменяется скриптом "First-Run" page. А когда $forward = false
- код public/index.php восстанавливается.
Стандартная обработка включает проверку версии PHP и перечень необходимых PHP-extensions. Эти настройки устанавливаются в "Open SkyProject". А список необходимых расширений PHP, можно найти автоматически с помощью "Global Reports".
Метод common_c::make_h($forward);
можно переопределить:
<?php
class common_c extends Controller
{
use HOOK_C;
. . .
static function make_h($forward) {
sqlf('delete from $_visitors');
sqlf('vacuum');
// + other: prepare for new instance
return Install::make($forward, [function () {
CLI && print("\nTimezone's 'first-run' written\n"); # this sample taken
return yml('+ @eval @inc(make) mvc/timezone.yaml'); # from HOLE.SKY. app
}]);
}
}
В примере выше, в параметре $plus
, передаётся дополнительный код, который будет включён в "First-Run" страницу. В массиве можно указать несколько дополнительных тестов (или код для начальной инициализации приложения). Передаваемая функция обратного вызова, должна возвращать в строке код дополнительного теста или код инициализации приложения.
Если все тесты "First-Run" прошли без ошибок, то public/index.php принимает свой обычный код, который содержится в конце файла "First-Run", после halt_compiler();
.
При создании *.sky файла с помощью "Open SkyProject", файл public/index.php также как и при sky master
, может замениться "First-Run" скриптом с помощью вызова common_c::make_h(true);
.
Работа с PHP web-сервером
SKY-приложения могут работать со встроенным в PHP development-сервером. Для этого необходимо выполнить: sky s
.
Типы консольных скриптов
Итак, для консольных скриптов, активирующихся планировщиком CRON имеется специальная схема и класс Schedule
. Главное преимущество: простое обслуживание и возможность запускать несколько скриптов параллельно, в отдельных процессах PHP, запуск которых совпал на одно и тоже время. Кроме того класс Schedule
, содержит весь другой типичный функционал, который может потребоваться для таких задач.
Также, имеется класс Console
и специальная схема для консольного скрипта sky. Скрипт "инициатор", можно запускать из любого места в файловой системе, если прописать к нему путь в PATH. Эта схема, также, инкапсулирует все типичные консольные задачи, которые могут потребоваться во время работы с Coresky. Класс Console
имеет удобную систему описания назначения скриптов (в DOC-комментариях), которая используется во время вывода "Usage".
Консольные скрипты, также, можно организовать "натурально":
<?php
define('START_TS', microtime(true));
require 'bootstrap.php';
$sky = new SKY;
require DIR_S . '/w2/mvc.php';
Plan::app_r('mvc/common_c.php'); # access to hooks
$sky->open(); # connect to database
echo 'test';
В этом случае, код приложения всё ещё будет использовать преимущества Coresky.