diff --git a/src/ZM/Event/SwooleEvent/OnManagerStart.php b/src/ZM/Event/SwooleEvent/OnManagerStart.php index 4c324f1a..11fefe80 100644 --- a/src/ZM/Event/SwooleEvent/OnManagerStart.php +++ b/src/ZM/Event/SwooleEvent/OnManagerStart.php @@ -46,7 +46,7 @@ class OnManagerStart implements SwooleEvent if (!Framework::$argv['disable-safe-exit']) { SignalListener::signalManager(); } - Framework::saveProcessState(ZM_PROCESS_MANAGER, $server->manager_pid); + ProcessManager::saveProcessState(ZM_PROCESS_MANAGER, $server->manager_pid); ProcessManager::createUserProcess('monitor', function () use ($server) { Process::signal(SIGINT, function () { diff --git a/src/ZM/Event/SwooleEvent/OnManagerStop.php b/src/ZM/Event/SwooleEvent/OnManagerStop.php index c1b92bf7..79fed871 100644 --- a/src/ZM/Event/SwooleEvent/OnManagerStop.php +++ b/src/ZM/Event/SwooleEvent/OnManagerStop.php @@ -8,7 +8,6 @@ use Swoole\Process; use ZM\Annotation\Swoole\SwooleHandler; use ZM\Console\Console; use ZM\Event\SwooleEvent; -use ZM\Framework; use ZM\Utils\Manager\ProcessManager; /** @@ -25,6 +24,6 @@ class OnManagerStop implements SwooleEvent } } Console::verbose('进程 Manager 已停止!'); - Framework::removeProcessState(ZM_PROCESS_MANAGER); + ProcessManager::removeProcessState(ZM_PROCESS_MANAGER); } } diff --git a/src/ZM/Event/SwooleEvent/OnShutdown.php b/src/ZM/Event/SwooleEvent/OnShutdown.php index d2f108c6..3cafa7c4 100644 --- a/src/ZM/Event/SwooleEvent/OnShutdown.php +++ b/src/ZM/Event/SwooleEvent/OnShutdown.php @@ -10,8 +10,8 @@ use Swoole\Server; use ZM\Annotation\Swoole\SwooleHandler; use ZM\Console\Console; use ZM\Event\SwooleEvent; -use ZM\Framework; use ZM\Utils\DataProvider; +use ZM\Utils\Manager\ProcessManager; /** * Class OnShutdown @@ -22,7 +22,7 @@ class OnShutdown implements SwooleEvent public function onCall(Server $server) { Console::verbose('正在关闭 Master 进程,pid=' . posix_getpid()); - Framework::removeProcessState(ZM_PROCESS_MASTER); + ProcessManager::removeProcessState(ZM_PROCESS_MASTER); if (DataProvider::scanDirFiles(_zm_pid_dir()) == []) { rmdir(_zm_pid_dir()); } diff --git a/src/ZM/Event/SwooleEvent/OnStart.php b/src/ZM/Event/SwooleEvent/OnStart.php index dd863e4a..07c574ec 100644 --- a/src/ZM/Event/SwooleEvent/OnStart.php +++ b/src/ZM/Event/SwooleEvent/OnStart.php @@ -10,6 +10,7 @@ use ZM\Config\ZMConfig; use ZM\Console\Console; use ZM\Event\SwooleEvent; use ZM\Framework; +use ZM\Utils\Manager\ProcessManager; use ZM\Utils\SignalListener; /** @@ -24,7 +25,7 @@ class OnStart implements SwooleEvent if (!Framework::$argv['disable-safe-exit']) { SignalListener::signalMaster($server); } - Framework::saveProcessState(ZM_PROCESS_MASTER, $server->master_pid, [ + ProcessManager::saveProcessState(ZM_PROCESS_MASTER, $server->master_pid, [ 'stdout' => ZMConfig::get('global')['swoole']['log_file'], 'daemon' => (bool) Framework::$argv['daemon'], ]); diff --git a/src/ZM/Event/SwooleEvent/OnWorkerExit.php b/src/ZM/Event/SwooleEvent/OnWorkerExit.php index 8da90aaf..2cf6e870 100644 --- a/src/ZM/Event/SwooleEvent/OnWorkerExit.php +++ b/src/ZM/Event/SwooleEvent/OnWorkerExit.php @@ -28,6 +28,6 @@ class OnWorkerExit implements SwooleEvent Coroutine::resume($v['coroutine']); } } - Console::info('正在结束 Worker #' . $worker_id . ',进程内可能有事务在运行...'); + Console::verbose('正在结束 Worker #' . $worker_id . ',进程内可能有事务在运行...'); } } diff --git a/src/ZM/Event/SwooleEvent/OnWorkerStop.php b/src/ZM/Event/SwooleEvent/OnWorkerStop.php index 3ecd8e06..16c994cf 100644 --- a/src/ZM/Event/SwooleEvent/OnWorkerStop.php +++ b/src/ZM/Event/SwooleEvent/OnWorkerStop.php @@ -10,8 +10,8 @@ use ZM\Config\ZMConfig; use ZM\Console\Console; use ZM\Container\WorkerContainer; use ZM\Event\SwooleEvent; -use ZM\Framework; use ZM\Store\LightCache; +use ZM\Utils\Manager\ProcessManager; /** * Class OnWorkerStop @@ -27,6 +27,6 @@ class OnWorkerStop implements SwooleEvent LightCache::savePersistence(); } Console::verbose(($server->taskworker ? 'Task' : '') . "Worker #{$worker_id} 已停止 (Worker 状态码: " . $server->getWorkerStatus($worker_id) . ')'); - Framework::removeProcessState($server->taskworker ? ZM_PROCESS_TASKWORKER : ZM_PROCESS_WORKER, $worker_id); + ProcessManager::removeProcessState($server->taskworker ? ZM_PROCESS_TASKWORKER : ZM_PROCESS_WORKER, $worker_id); } } diff --git a/src/ZM/Utils/Manager/ProcessManager.php b/src/ZM/Utils/Manager/ProcessManager.php index 143e5109..727850b1 100644 --- a/src/ZM/Utils/Manager/ProcessManager.php +++ b/src/ZM/Utils/Manager/ProcessManager.php @@ -7,6 +7,8 @@ declare(strict_types=1); namespace ZM\Utils\Manager; use Swoole\Process; +use ZM\Exception\ZMKnownException; +use ZM\Utils\DataProvider; class ProcessManager { @@ -22,4 +24,152 @@ class ProcessManager { return self::$user_process[$string] ?? null; } + + /** + * @param null|int|string $id_or_name + * @throws ZMKnownException + * @internal + */ + public static function removeProcessState(int $type, $id_or_name = null) + { + switch ($type) { + case ZM_PROCESS_MASTER: + $file = _zm_pid_dir() . '/master.json'; + if (file_exists($file)) { + unlink($file); + } + return; + case ZM_PROCESS_MANAGER: + $file = _zm_pid_dir() . '/manager.pid'; + if (file_exists($file)) { + unlink($file); + } + return; + case ZM_PROCESS_WORKER: + if (!is_int($id_or_name)) { + throw new ZMKnownException('E99999', 'worker_id必须为整数'); + } + $file = _zm_pid_dir() . '/worker.' . $id_or_name . '.pid'; + if (file_exists($file)) { + unlink($file); + } + return; + case ZM_PROCESS_USER: + if (!is_string($id_or_name)) { + throw new ZMKnownException('E99999', 'process_name必须为字符串'); + } + $file = _zm_pid_dir() . '/user.' . $id_or_name . '.pid'; + if (file_exists($file)) { + unlink($file); + } + return; + case ZM_PROCESS_TASKWORKER: + if (!is_int($id_or_name)) { + throw new ZMKnownException('E99999', 'worker_id必须为整数'); + } + $file = _zm_pid_dir() . '/taskworker.' . $id_or_name . '.pid'; + if (file_exists($file)) { + unlink($file); + } + return; + } + } + + /** + * 用于框架内部获取多进程运行状态的函数 + * + * @param mixed $id_or_name + * @throws ZMKnownException + * @return false|int|mixed + * @internal + */ + public static function getProcessState(int $type, $id_or_name = null) + { + $file = _zm_pid_dir(); + switch ($type) { + case ZM_PROCESS_MASTER: + if (!file_exists($file . '/master.json')) { + return false; + } + $json = json_decode(file_get_contents($file . '/master.json'), true); + if ($json !== null) { + return $json; + } + return false; + case ZM_PROCESS_MANAGER: + if (!file_exists($file . '/manager.pid')) { + return false; + } + return intval(file_get_contents($file . '/manager.pid')); + case ZM_PROCESS_WORKER: + if (!is_int($id_or_name)) { + throw new ZMKnownException('E99999', 'worker_id必须为整数'); + } + if (!file_exists($file . '/worker.' . $id_or_name . '.pid')) { + return false; + } + return intval(file_get_contents($file . '/worker.' . $id_or_name . '.pid')); + case ZM_PROCESS_USER: + if (!is_string($id_or_name)) { + throw new ZMKnownException('E99999', 'process_name必须为字符串'); + } + if (!file_exists($file . '/user.' . $id_or_name . '.pid')) { + return false; + } + return intval(file_get_contents($file . '/user.' . $id_or_name . '.pid')); + case ZM_PROCESS_TASKWORKER: + if (!is_int($id_or_name)) { + throw new ZMKnownException('E99999', 'worker_id必须为整数'); + } + if (!file_exists($file . '/taskworker.' . $id_or_name . '.pid')) { + return false; + } + return intval(file_get_contents($file . '/taskworker.' . $id_or_name . '.pid')); + default: + return false; + } + } + + /** + * 将各进程的pid写入文件,以备后续崩溃及僵尸进程处理使用 + * + * @param int|string $pid + * @internal + */ + public static function saveProcessState(int $type, $pid, array $data = []) + { + switch ($type) { + case ZM_PROCESS_MASTER: + $file = _zm_pid_dir() . '/master.json'; + $json = [ + 'pid' => intval($pid), + 'stdout' => $data['stdout'], + 'daemon' => $data['daemon'], + ]; + file_put_contents($file, json_encode($json, JSON_UNESCAPED_UNICODE)); + return; + case ZM_PROCESS_MANAGER: + $file = _zm_pid_dir() . '/manager.pid'; + file_put_contents($file, strval($pid)); + return; + case ZM_PROCESS_WORKER: + $file = _zm_pid_dir() . '/worker.' . $data['worker_id'] . '.pid'; + file_put_contents($file, strval($pid)); + return; + case ZM_PROCESS_USER: + $file = _zm_pid_dir() . '/user.' . $data['process_name'] . '.pid'; + file_put_contents($file, strval($pid)); + return; + case ZM_PROCESS_TASKWORKER: + $file = _zm_pid_dir() . '/taskworker.' . $data['worker_id'] . '.pid'; + file_put_contents($file, strval($pid)); + return; + } + } + + public static function isStateEmpty(): bool + { + $ls = DataProvider::scanDirFiles(_zm_pid_dir(), false, true); + return empty($ls); + } }