Работа с 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
Выполнение задач в едином потоке
Иногда функция 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)
app _test Test without DB
app test This is just test
c Show controllers
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 ware `venus` 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]
v Show Coresky version
venus base Work with database
venus caret Friend classes
venus im Debug Maxwell indexes
venus iv Debug Vesper index
venus parse Parse css
venus s Search (list) Vesper css classes
venus t Show Venus tables
venus test Test Maat parser
venus tw Generate Vesper(Tailwind) classes
w List installed wares
warm Warm all cache
Coresky app: βῆτα.0.788.AB.SKY. (ab.sky)
Coresky ware: venus
Repository: https://github.com/energy-coresky/venus.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, содержащий путь к приложению. Таким образом, консольные команды приложений, можно выполнять в том числе из директорий продуктов.
Работа с 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 __DIR__ . '/../bootstrap.php';
new SKY;
echo 'test';
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
Install::make($forward, ['common_c::trivial']);
}
static function trivial() {
return ['This is a trivial test. Hit "Run app anyway" if all other OK', false];
}
}
В примере выше, в параметре $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);
.