mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-07-06 16:25:36 +08:00
Signal handling fixes: - SignalListener: add SIGHUP/SIGTERM handling for both Swoole and Workerman drivers in master and worker processes - Prevent 100% CPU when IDE terminal is closed by ensuring graceful shutdown on terminal hangup PHP version support: - Widen PHP constraint to 8.3, 8.4, 8.5 - Bump doctrine/dbal from ^2.13.1 to ^4.4 - Bump php-cs-fixer to ^3.64, phpstan to ^1.12 - Bump swoole/ide-helper to ^5.0 - Drop phpunit ^8.5 (EOL), keep ^9.0 CI updates: - actions/checkout@v3 → @v4 (Node.js 20 deprecated) - Bump static analysis/code style PHP from 8.1 to 8.3
172 lines
6.1 KiB
PHP
172 lines
6.1 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace ZM\Process;
|
||
|
||
use OneBot\Driver\Process\ProcessManager;
|
||
use ZM\Exception\ZMKnownException;
|
||
use ZM\Store\FileSystem;
|
||
|
||
class ProcessStateManager
|
||
{
|
||
public static array $process_mode = [];
|
||
|
||
/**
|
||
* 查看是否为多 Worker 模式,插件可能用得到
|
||
*/
|
||
public static function isMultiWorkers(): bool
|
||
{
|
||
return (self::$process_mode['worker'] ?? 1) > 1;
|
||
}
|
||
|
||
public static function isTaskWorker(): bool
|
||
{
|
||
return (ProcessManager::getProcessType() & ONEBOT_PROCESS_TASKWORKER) !== 0;
|
||
}
|
||
|
||
/**
|
||
* 删除进程运行状态
|
||
*
|
||
* @throws ZMKnownException
|
||
* @internal
|
||
*/
|
||
public static function removeProcessState(int $type, int|string|null $id_or_name = null): void
|
||
{
|
||
switch ($type) {
|
||
case ZM_PROCESS_MASTER:
|
||
$file = zm_dir(ZM_STATE_DIR . '/master.json');
|
||
if (file_exists($file)) {
|
||
unlink($file);
|
||
}
|
||
return;
|
||
case ZM_PROCESS_MANAGER:
|
||
$file = zm_dir(ZM_STATE_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_dir(ZM_STATE_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_dir(ZM_STATE_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_dir(ZM_STATE_DIR . '/taskworker.' . $id_or_name . '.pid');
|
||
if (file_exists($file)) {
|
||
unlink($file);
|
||
}
|
||
return;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 用于框架内部获取多进程运行状态的函数
|
||
*
|
||
* @return false|int|mixed
|
||
* @throws ZMKnownException
|
||
* @internal
|
||
*/
|
||
public static function getProcessState(int $type, mixed $id_or_name = null): mixed
|
||
{
|
||
$file = ZM_STATE_DIR;
|
||
switch ($type) {
|
||
case ZM_PROCESS_MASTER:
|
||
if (!file_exists(zm_dir($file . '/master.json'))) {
|
||
return false;
|
||
}
|
||
$json = json_decode(file_get_contents(zm_dir($file . '/master.json')), true);
|
||
return $json ?? false;
|
||
case ZM_PROCESS_MANAGER:
|
||
if (!file_exists(zm_dir($file . '/manager.pid'))) {
|
||
return false;
|
||
}
|
||
return intval(file_get_contents(zm_dir($file . '/manager.pid')));
|
||
case ZM_PROCESS_WORKER:
|
||
if (!is_int($id_or_name)) {
|
||
throw new ZMKnownException('E99999', 'worker_id必须为整数');
|
||
}
|
||
if (!file_exists(zm_dir($file . '/worker.' . $id_or_name . '.pid'))) {
|
||
return false;
|
||
}
|
||
return intval(file_get_contents(zm_dir($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(zm_dir($file . '/user.' . $id_or_name . '.pid'))) {
|
||
return false;
|
||
}
|
||
return intval(file_get_contents(zm_dir($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(zm_dir($file . '/taskworker.' . $id_or_name . '.pid'))) {
|
||
return false;
|
||
}
|
||
return intval(file_get_contents(zm_dir($file . '/taskworker.' . $id_or_name . '.pid')));
|
||
default:
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 将各进程的pid写入文件,以备后续崩溃及僵尸进程处理使用
|
||
*
|
||
* @internal
|
||
*/
|
||
public static function saveProcessState(int $type, int|string $pid, array $data = []): void
|
||
{
|
||
switch ($type) {
|
||
case ZM_PROCESS_MASTER:
|
||
$file = zm_dir(ZM_STATE_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_dir(ZM_STATE_DIR . '/manager.pid');
|
||
file_put_contents($file, strval($pid));
|
||
return;
|
||
case ZM_PROCESS_WORKER:
|
||
$file = zm_dir(ZM_STATE_DIR . '/worker.' . $data['worker_id'] . '.pid');
|
||
file_put_contents($file, strval($pid));
|
||
return;
|
||
case ZM_PROCESS_USER:
|
||
$file = zm_dir(ZM_STATE_DIR . '/user.' . $data['process_name'] . '.pid');
|
||
file_put_contents($file, strval($pid));
|
||
return;
|
||
case ZM_PROCESS_TASKWORKER:
|
||
$file = zm_dir(ZM_STATE_DIR . '/taskworker.' . $data['worker_id'] . '.pid');
|
||
file_put_contents($file, strval($pid));
|
||
return;
|
||
}
|
||
}
|
||
|
||
public static function isStateEmpty(): bool
|
||
{
|
||
$ls = FileSystem::scanDirFiles(ZM_STATE_DIR, false, true);
|
||
return empty($ls);
|
||
}
|
||
}
|