заметки для памяти
Поставил мастер спустя год. Вношу правки свои. Предупреждаю, система на Вин10, база на рам-диске, ПУ нет.
Апач, mySQL, VLC - всё работает службами (ну, и редис службой - он у меня остался в одном месте из-за железа)
Связь с внешним миром - через Телеграм и Connect. Стоит УПС. Минут 40 он держит МДМ с роутерами, потом штатно гасит всё.
Из-за этого нюансы (всё равно, бд в памяти) - отказался от редиса как кэша, все таблицы мемори перевел в майисам -- это расширило возможности кэша, поле DATAVALUE в таблице cached_values сделал varchar(2048)
Соответственно, в \lib\caching.class.php замена
255 на 2048
function saveToCache($key, $value)
{
if (is_array($value) || strlen($value) > 2048) {
return;
}
Общее замечание - считаю, что хранить время обновления циклов и их контроль в свойствах - излишне. До обновления на мастер отлично работало в кэше только, без заведения свойств. План на будущее - сделать и тут так же.
Циклы привел к общему формату - использование переменной имени
$cycleVarName = 'ThisComputer.'.str_replace('.php', '', basename(__FILE__)).'Run';
setGlobal($cycleVarName, time(), 1);
проверка что работает
while (1) {
if (time() - $checked_time > 20) {
$checked_time = time();
setGlobal($cycleVarName, $checked_time, 1);
}
...
схема цикла в общем случае:
//настройки цикла
...
$checked_time = 0;
$cycleVarName = 'ThisComputer.'.str_replace('.php', '', basename(__FILE__)).'Run';
setGlobal($cycleVarName, time(), 1);
echo date("H:i:s") . " running " . basename(__FILE__) . PHP_EOL;
while (1)
{
if (time() - $checked_time > 20)
{
$checked_time = time();
setGlobal($cycleVarName, $checked_time, 1); //отметим, что цикл живой
}
...
//тело цикла
...
if (isRebootRequired() || IsSet($_GET['onetime'])) //выход из цикла
{
exit;
}
sleep(1);
}
DebMes("Unexpected close of cycle: " . basename(__FILE__));
\scripts\cycle_phistory.php:
что сделано - замечено, что для отображения переполнения очереди истории используется свойство phistory_queue_problem, которое каждую секунду опрашивается.
Исправил так, с сохранением вывода ошибки переполнения
...
$limit = (int)gg('phistory_queue_limit');
if (!$limit) {
$limit = 200;
}
$limit_plus = $limit +1; //добавлено для определения выхода за лимит
...
$queue_error_status = 0; //введем переменную статуса ошибки
while (1) {
if (time() - $checked_time > 20) {
$checked_time = time();
setGlobal($cycleVarName, $checked_time, 1);
}
//$queue_error_status = gg('phistory_queue_problem');
//$tmp = SQLSelectOne("SELECT COUNT(*) as TOTAL FROM phistory_queue;");
//$count_queue = (int)$tmp['TOTAL'];
$queue = SQLSelect("SELECT * FROM phistory_queue ORDER BY ID LIMIT ". $limit_plus);
if ($queue[0]['ID']) {
$total = count($queue);
if($total > $limit && !$queue_error_status){
//sg('phistory_queue_problem',1);
$queue_error_status = 1;
$txt = 'Properties history queue is too long ('.$total.')';
echo date("H:i:s") . " " . $txt . "\n";
registerError('phistory_queue',$txt);
} elseif ($total <= $limit && $queue_error_status) {
//sg('phistory_queue_problem',0);
$queue_error_status = 0;
}
\scripts\cycle_main.php:
Тут рассуждения такие - тут каждую 20 (после исправления, в исходнике - каждую 5) секунду в цикле пишется в свойства ThisComputer.uptime общее время работы и в ThisComputer.uptimeText форматированное время работы с точностью до минуты). Оба эти свойства зависят только от ThisComputer.started_time и текущего времени. Заполнение их я из цикла выкинул и добавил в скрипт, который вызывается раз в минуту
while (1) {
if (time() - $checked_time > 20) {
$checked_time = time();
setGlobal($cycleVarName, $checked_time, 1);
//$timestamp = time() - $started_time;
//setGlobal('ThisComputer.uptime', $timestamp);
/*
$years = floor($timestamp / 31536000);
$days = floor(($timestamp - ($years * 31536000)) / 86400);
$hours = floor(($timestamp - ($years * 31536000 + $days * 86400)) / 3600);
$minutes = floor(($timestamp - ($years * 31536000 + $days * 86400 + $hours * 3600)) / 60);
$timestring = '';
if ($years > 0) {
$timestring .= $years . 'y ';
}
if ($days > 0) {
$timestring .= $days . 'd ';
}
if ($hours > 0) {
$timestring .= $hours . 'h ';
}
if ($minutes > 0) {
$timestring .= $minutes . 'm ';
}
setGlobal('ThisComputer.uptimeText', trim($timestring));
*/
}
...
скрипт:
$started_time = getGlobal('ThisComputer.started_time');
$timestamp = time() - $started_time;
//setGlobal('ThisComputer.uptime', $timestamp);
saveToCache('MJD:ThisComputer.UPTIME', $timestamp); //сохраняем только в кэш, потому что это нафиг не надо хранить в базе
$years = floor($timestamp / 31536000);
$days = floor(($timestamp - ($years*31536000)) / 86400);
$hours = floor(($timestamp - ($years*31536000 + $days*86400)) / 3600);
$minutes = floor(($timestamp - ($years*31536000 + $days*86400 + $hours*3600)) / 60);
$timestring = '';
if ($years > 0){
$timestring .= $years . 'г '; //заодно, на русский переведем
}
if ($days > 0) {
$timestring .= $days . 'д ';
}
if ($hours > 0) {
$timestring .= $hours . 'ч ';
}
if ($minutes > 0) {
$timestring .= $minutes . 'м ';
}
//setGlobal('ThisComputer.uptimeText', trim($timestring));
saveToCache('MJD:ThisComputer.uptimeText', trim($timestring));//сохраняем только в кэш, потому что это нафиг не надо хранить в базе
postToWebSocketQueue('ThisComputer.uptimeText',trim($timestring)); //отошлём в интерфейс
Цикл cycle.php
Вот эту часть, где, как я понимаю, ищем циклы с непустым Контрол и останавливаем или перезапускаем
...
$qry = "OBJECT_ID=" . $thisComputerObject->id . " AND (TITLE LIKE 'cycle%Run' OR TITLE LIKE 'cycle%Control')";
$cycles = SQLSelect("SELECT properties.* FROM properties WHERE $qry ORDER BY TITLE");
$total = count($cycles);
$seen = array();
for ($i = 0; $i < $total; $i++) {
$title = $cycles[$i]['TITLE'];
$title = preg_replace('/Run$/', '', $title);
$title = preg_replace('/Control$/', '', $title);
if (isset($seen[$title])) {
continue;
}
$seen[$title] = 1;
$control = getGlobal($title . 'Control');
if ($control != '') {
DebMes("Got control command '$control' for " . $title, 'threads');
if ($control == 'stop') {
$to_stop[$title] = time();
} elseif ($control == 'restart' || $control == 'start') {
$to_stop[$title] = time();
$to_start[$title] = time() + 30;
}
setGlobal($title . 'Control', '');
}
}
...
переписал на:
...
//не получить ли просто список циклов с непустым Контрол?
$qry = "SELECT REPLACE(REPLACE( KEYWORD, 'Control', '' ),'MJD:ThisComputer.','') TITLE,DATAVALUE control FROM `cached_values` WHERE `KEYWORD` like 'MJD:ThisComputer.cycle%Control' and DATAVALUE>''"; // fix 2021-04-20
$cycles = SQLSelect($qry);
$total = count($cycles);
for ($i = 0; $i < $total; $i++) {
$title = $cycles[$i]['TITLE']; //возьмём титле
$control = $cycles[$i]['control'];//команда
DebMes("Got control command '$control' for ".$title,'threads');
if ($control == 'stop') {
$to_stop[$title] = time();
} elseif ($control == 'restart' || $control == 'start') {
$to_stop[$title] = time();
$to_start[$title] = time() + 30;
}
setGlobal('ThisComputer.'.$title.'Control','');
}
...
Цикл веб-сокетов:
upd 06/09/2021
в файле цикла
$cycleNameWS = 'ThisComputer.'.str_replace('.php', '', basename(__FILE__)).'Run';
//setGlobal($cycleName, time(), 1);
saveToCache('MJD:'.$cycleNameWS,time());
В файле MajordomoApplication.php
global $cycleNameWS;
if ($cycleNameWS) {
$checked_time = time();
//setGlobal($cycleName, $checked_time, 1);
saveToCache('MJD:'.$cycleNameWS, $checked_time);
$cycleName заменил на $cycleNameWS чтобы не перепутать + переход на кэш
избавляемся в мастере от чересчур частой чистки
в common.class.php функция runScheduledJobs() приводим к такому виду первые строки:
if (date('s')=="10") {
SQLExec("DELETE FROM jobs WHERE EXPIRE <= '" . date('Y-m-d H:i:s') . "'");
}
$sqlQuery = "SELECT *
FROM jobs
WHERE PROCESSED = 0
AND EXPIRED = 0
AND RUNTIME <= '" . date('Y-m-d H:i:s') . "' AND EXPIRE > '" . date('Y-m-d H:i:s') . "'";
\load_settings.php:
$offset = timezone_offset_get(new DateTimeZone(SETTINGS_SITE_TIMEZONE), new DateTime());
$offset_text = timezone_offset_string($offset);
//SQLExec("SET time_zone = '" . $offset_text . "';"); // избавляемся от частых запросов
\lib\mysqli.class.php:
$this->latestTransaction=time();
//$this->Exec("set NAMES 'utf8', CHARACTER SET 'utf8', character_set_client='utf8', character_set_results='utf8', collation_connection='utf8_general_ci';");// избавляемся от частых запросов
return 1;
Старое моё - исправлен формат даты в Панели управл...
будет дополняться...
Домодедово, Россия
На форуме: xor