<?php
function startWith($str, $prefix) {
if (strlen($prefix) > strlen($str)) {
return false;
}
return substr($str, 0, strlen($prefix)) === $prefix;
}
/**
* @param $daemonName string
* @param $callback callback
* @param $processAmount int
* @param $timeOut if it's not zero, child process will exit after $timeOut seconds
*/
function restartDaemons($daemonName, $callback, $processAmount = 1, $timeOut = 0)
{
$daemonName = strtolower($daemonName);
// control child processes via file existence
$pidDir = RUNTIME_PATH . DIRECTORY_SEPARATOR . 'pid';
if (!is_dir($pidDir)) {
mkdir($pidDir, 0777, true);
}
//clear pid files
$pidDirHandle = opendir($pidDir);
while ($fileName = readdir($pidDirHandle)) {
if (startWith($fileName, $daemonName . '.worker.')) {
@unlink($pidDir . DIRECTORY_SEPARATOR . $fileName);
echo 'CLEAN_PID_FILE' . "\n";
}
}
for ($i = 0; $i < $processAmount; $i++) {
$pid = pcntl_fork();
if ($pid == 0) {
//child processe logic
$pid = getmypid();
$pidFile = $pidDir . DIRECTORY_SEPARATOR . $daemonName . '.worker.' . $pid;
touch($pidFile);
echo "worker start: " . ($i + 1) . "/$processAmount" . PHP_EOL;
$startDaemonTime[$i] = microtime(true);
while (file_exists($pidFile)) {
if($timeOut > 0 && microtime(true) - $startDaemonTime[$i] > $timeOut){
break;
}
$roundStartTime = microtime(true);
$runSuccess = $callback($processAmount, $i);
if (!$runSuccess) {
sleep(1);
} else {
}
}
echo "worker exit: " . ($i + 1) . "/$processAmount" . PHP_EOL;
exit(0);
}
}
//parent process waits for child processes
for ($i = 0; $i < $processAmount; $i++) {
$spId = pcntl_wait($status);
if ($status != 0) {
}
}
}
restartDaemons('haha', function() {return true;}, 10, 10);