<?php $running = true; $exitSig = 0; function signal($sig) { global $running, $exitSig, $T; if($sig == SIGUSR2) { $T = 1; return; } $running = false; $exitSig = $sig; task_set_run(false); } pcntl_async_signals(true); pcntl_signal(SIGTERM, 'signal', false); pcntl_signal(SIGINT, 'signal', false); pcntl_signal(SIGUSR1, 'signal', false); pcntl_signal(SIGUSR2, 'signal', false); if(empty($_SERVER['argv'][1])) exit("usage: {$_SERVER['_']} {$_SERVER['argv'][0]} <inifile> [isdebug [timefile [lockfile]]]\n"); define('FILE', $_SERVER['argv'][1]); define('DEBUG', $_SERVER['argv'][2]??0); define('TIME', $_SERVER['argv'][3]??FILE.'.time'); define('LOCK', $_SERVER['argv'][4]??FILE.'.lock'); define('KEYS', ['Y', 'm', 'd', 'w', 'H', 'i', 's']); is_file(FILE) or die("ini file not exists\n"); is_file(LOCK) and die("running...\n"); touch(LOCK); ini_set('memory_limit', -1); $time = microtime(true); share_var_init(); $T = 0; $crons = []; $times = (($t = @file_get_contents(TIME))?(json_decode($t, true)?:[]):[]); $time = microtime(true); while($running) { clearstatcache(true, FILE); if($T != ($t = filemtime(FILE))) { if($T) { $s = date('H:i:s'); echo "[$s] RELOAD\n"; file_put_contents(TIME, json_encode($times, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE)); } $T = $t; task_wait(SIGINT); task_set_run($running); if(!$running) break; $cfgs = parse_ini_file(FILE, true, INI_SCANNER_RAW); if($cfgs === false) { echo error_get_last()['message']; break; } cfg_vars($cfgs); foreach($cfgs as $key => &$cfg) { if(!isset($cfg['type'])) { echo "No type parameter at key '$key'\n"; unset($cfgs[$key]); $running = false; continue; } $cfg['type'] = strtolower($cfg['type']); switch($cfg['type']) { case 'php': case 'once': case 'script': case 'daemon': if($cfg['type'] === 'once') $n = 1; else $n = max(1, $cfg['count'] ?? 1); for($i=0; $i<$n; $i++) { if(!DEBUG && !create_task($key, $cfg['file'], $cfg['args']??[], $cfg['logfile']??null, $cfg['logmode']??'ab')) { echo "create task $key failure\n"; } } unset($cfgs[$key]); case 'cron': if(!isset($cfg['file'])) { echo "No file parameter at key '$key'\n"; unset($cfgs[$key]); $running = false; } if($cfg['type'] === 'cron' && !isset($cfg['cron'])) { echo "No cron parameter at key '$key'\n"; unset($cfgs[$key]); $running = false; } break; default: echo "unknown type '{$cfg['type']}' at key '$key'\n"; unset($cfgs[$key]); $running = false; break; } } unset($cfg); if(!$running) break; } isset($ctime) and ($t = 1000000 - 1000000 * (microtime(true) - $time)) >= 0 and usleep($t); $time = microtime(true); $ctime = (int) $time; $a1 = array_combine(KEYS, explode(' ', date('Y m d w H i s', $ctime))); if(DEBUG) { $isHas = false; $t = implode(' ', $a1); echo "$t\n"; } foreach($cfgs as $key => &$cfg) { if(isset($crons[$key])) { if(task_is_run($crons[$key])) continue; else unset($crons[$key]); } if(!isset($times[$key])) { $times[$key] = $ctime; continue; } $a0 = preg_split('/\s/', '* ' . $cfg['cron']); if(count($a0) != count(KEYS)) { echo "Unknown cron '{$cfg['cron']}' parameter size at key '$key'\n"; continue; } $mtime = $times[$key]; $a0 = array_combine(KEYS, $a0); $isNext = true; foreach($a0 as $k=>$v) { if($v === '*') continue; if(!preg_match('/^(\*\/)?\d+$/', $v)) { echo "Error cron parameter '$k' => '$v' at key '$key'\n"; continue; } if(!strncmp($v, '*/', 2)) { $v = max(1, (int) substr($v, 2)); switch($k) { case 'm': @list($Y, $m) = explode(' ', date('Y m', $mtime)); $t = ($a1['Y'] - $Y) * 12 + $a1['m'] - $m; break; case 'd': $t = ($ctime - $mtime) / 86400; break; case 'w': $t = ($ctime - $mtime) / (7 * 86400); break; case 'H': $t = ($ctime - $mtime) / 3600; break; case 'i': $t = ($ctime - $mtime) / 60; break; case 's': $t = $ctime - $mtime; break; default: $t = 0; break; } if($t < $v) { $isNext = false; break; } } else { if($v != $a1[$k]) { $isNext = false; break; } } } if($isNext) { if(DEBUG) { $isHas = true; echo "-------------------------\n"; var_dump($key, $cfg); } if(!DEBUG && !create_task($key, $cfg['file'], $cfg['args']??[], $cfg['logfile']??null, $cfg['logmode']??'ab', $crons[$key])) { echo "create task $key failure\n"; } else { $times[$key] = $ctime; } } } unset($cfg); if(DEBUG && $isHas) echo "-------------------------\n"; } task_wait($exitSig?:SIGINT); $crons = null; share_var_destory(); file_put_contents(TIME, json_encode($times, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE)); unlink(LOCK); if($exitSig == SIGUSR1) { $s = date('H:i:s'); echo "[$s] RESTART\n"; } function cfg_vars(array &$vars) { foreach($vars as &$var) { if(is_array($var)) cfg_vars($var); else $var = preg_replace_callback('/\$\{?([a-z_][0-9a-z_]*)\}?/i', function($matches) { return getenv($matches[1]); }, $var); } }