mirror of
https://gitee.com/zoujingli/ThinkAdmin.git
synced 2026-06-07 12:38:11 +08:00
fix: 由于部分使用场景异常,去除文件动态监听与内存监控重启
This commit is contained in:
parent
056ade708f
commit
a85cdf49d8
@ -58,22 +58,6 @@ return [
|
||||
// 进程数量
|
||||
'count' => 4,
|
||||
],
|
||||
// 监控文件变更重载
|
||||
'files' => [
|
||||
// 监控检测间隔(单位秒,零不监控)
|
||||
'time' => 3,
|
||||
// 文件监控目录(默认监控 app+config 目录)
|
||||
'path' => [],
|
||||
// 文件监控后缀(默认监控 所有 文件)
|
||||
'exts' => ['*']
|
||||
],
|
||||
// 监控内存超限重载
|
||||
'memory' => [
|
||||
// 监控检测间隔(单位秒,零不监控)
|
||||
'time' => 60,
|
||||
// 限制内存大小(可选单位有 G M K )
|
||||
'limit' => '1G'
|
||||
],
|
||||
// 自定义服务配置(可选)
|
||||
'customs' => [
|
||||
// 自定义 text 服务
|
||||
|
||||
@ -1,253 +0,0 @@
|
||||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | Worker Plugin for ThinkAdmin
|
||||
// +----------------------------------------------------------------------
|
||||
// | 版权所有 2014~2024 ThinkAdmin [ thinkadmin.top ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网站: https://thinkadmin.top
|
||||
// +----------------------------------------------------------------------
|
||||
// | 免责声明 ( https://thinkadmin.top/disclaimer )
|
||||
// | 开源协议 ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// | 参考资料 ( https://github.com/walkor/webman/blob/master/process/Monitor.php )
|
||||
// +----------------------------------------------------------------------
|
||||
// | gitee 代码仓库:https://gitee.com/zoujingli/think-plugs-worker
|
||||
// | github 代码仓库:https://github.com/zoujingli/think-plugs-worker
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace plugin\worker;
|
||||
|
||||
use FilesystemIterator;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use SplFileInfo;
|
||||
use think\admin\service\ProcessService;
|
||||
use Workerman\Timer;
|
||||
use Workerman\Worker;
|
||||
|
||||
/**
|
||||
* 资源监控管理器
|
||||
* @class Monitor
|
||||
* @package plugin\worker
|
||||
*/
|
||||
abstract class Monitor
|
||||
{
|
||||
/**
|
||||
* 监控目录
|
||||
* @var array
|
||||
*/
|
||||
private static $paths = [];
|
||||
|
||||
/**
|
||||
* 内存限制
|
||||
* @var string
|
||||
*/
|
||||
private const defaultMaxMemory = '1G';
|
||||
|
||||
/**
|
||||
* 暂停锁定标记
|
||||
* @var string
|
||||
*/
|
||||
private static $lockFile;
|
||||
private static $changeTimerId = -1;
|
||||
private static $memoryTimerId = -1;
|
||||
|
||||
/**
|
||||
* 监听锁定标记
|
||||
* @return string
|
||||
*/
|
||||
private static function _tag(): string
|
||||
{
|
||||
return self::$lockFile ?: (self::$lockFile = syspath('runtime/monitor.lock'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause Monitor
|
||||
* @return void
|
||||
*/
|
||||
public static function pause()
|
||||
{
|
||||
file_put_contents(self::_tag(), time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume monitor
|
||||
* @return void
|
||||
*/
|
||||
public static function resume(): void
|
||||
{
|
||||
clearstatcache();
|
||||
if (is_file(self::_tag())) {
|
||||
unlink(self::$lockFile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether monitor is paused
|
||||
* @return bool
|
||||
*/
|
||||
public static function isPaused(): bool
|
||||
{
|
||||
clearstatcache();
|
||||
return file_exists(self::_tag());
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Files Monitor
|
||||
* @param array $dirs 监听目录
|
||||
* @param array $exts 文件后缀
|
||||
* @param integer $interval 定时器时间
|
||||
* @return boolean
|
||||
*/
|
||||
public static function enableChangeMonitor(array $dirs = [], array $exts = ['php'], int $interval = 60): bool
|
||||
{
|
||||
if ($interval <= 0) return false;
|
||||
if (!Worker::getAllWorkers()) return false;
|
||||
if (in_array('exec', explode(',', ini_get('disable_functions')), true)) {
|
||||
echo "\nMonitor file change turned off because exec() has been disabled by disable_functions setting in " . PHP_CONFIG_FILE_PATH . "/php.ini\n";
|
||||
return false;
|
||||
} else {
|
||||
foreach ($dirs as $dir) self::$paths[$dir] = $exts;
|
||||
if (self::$changeTimerId > -1) Timer::del(self::$changeTimerId);
|
||||
self::$changeTimerId = Timer::add($interval, static function () {
|
||||
if (self::isPaused()) return false;
|
||||
foreach (self::$paths as $path => $exts) {
|
||||
if (self::_checkFilesChange($path, $exts)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Files Change
|
||||
* @param string $path
|
||||
* @param array $exts
|
||||
* @return boolean
|
||||
*/
|
||||
private static function _checkFilesChange(string $path, array $exts): bool
|
||||
{
|
||||
static $lastMtime, $tooManyFilesCheck;
|
||||
if (!$lastMtime) $lastMtime = time();
|
||||
|
||||
clearstatcache();
|
||||
if (!is_dir($path)) {
|
||||
if (!is_file($path)) return false;
|
||||
$iterator = [new SplFileInfo($path)];
|
||||
} else {
|
||||
// recursive traversal directory
|
||||
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS));
|
||||
}
|
||||
$count = 0;
|
||||
foreach ($iterator as $file) {
|
||||
$count++;
|
||||
/** var SplFileInfo $file */
|
||||
if (is_dir($file->getRealPath())) continue;
|
||||
// check mtime
|
||||
if ($lastMtime < $file->getMTime() && (in_array('*', $exts) || in_array($file->getExtension(), $exts, true))) {
|
||||
if ($file->getExtension() === 'php') {
|
||||
exec(ProcessService::php("-l {$file}"), $out, $var);
|
||||
if ($var) continue;
|
||||
}
|
||||
$lastMtime = $file->getMTime();
|
||||
echo "{$file} update and reload\n";
|
||||
// send SIGUSR1 signal to master process for reload
|
||||
if (DIRECTORY_SEPARATOR === '/') {
|
||||
posix_kill(posix_getppid(), SIGUSR1);
|
||||
break;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$tooManyFilesCheck && $count > 10000) {
|
||||
echo "Monitor: There are too many files ($count files) in $path which makes file monitoring very slow\n";
|
||||
$tooManyFilesCheck = 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Member Monitor,only windows
|
||||
* @param ?string $limit
|
||||
* @param integer $interval
|
||||
* @return boolean
|
||||
*/
|
||||
public static function enableMemoryMonitor(?string $limit = null, int $interval = 60): bool
|
||||
{
|
||||
if ($interval <= 0) return false;
|
||||
if (!Worker::getAllWorkers()) return false;
|
||||
if (!ProcessService::isUnix()) return false;
|
||||
if ($memoryLimit = self::_getMemoryLimit($limit ?: self::defaultMaxMemory)) {
|
||||
self::$memoryTimerId > -1 && Timer::del(self::$memoryTimerId);
|
||||
self::$memoryTimerId = Timer::add($interval, [self::class, 'checkMemory'], [$memoryLimit]);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Memory Limit
|
||||
* @param $memoryLimit
|
||||
* @return void
|
||||
*/
|
||||
public static function checkMemory($memoryLimit)
|
||||
{
|
||||
if (static::isPaused() || $memoryLimit <= 0) return;
|
||||
$ppid = posix_getppid();
|
||||
$childrenFile = "/proc/$ppid/task/$ppid/children";
|
||||
if (!is_file($childrenFile) || !($children = file_get_contents($childrenFile))) {
|
||||
return;
|
||||
}
|
||||
foreach (explode(' ', $children) as $pid) {
|
||||
$pid = (int)$pid;
|
||||
$statusFile = "/proc/$pid/status";
|
||||
if (!is_file($statusFile) || !($status = file_get_contents($statusFile))) {
|
||||
continue;
|
||||
}
|
||||
$mem = 0;
|
||||
if (preg_match('/VmRSS\s*?:\s*?(\d+?)\s*?kB/', $status, $match)) {
|
||||
$mem = $match[1];
|
||||
}
|
||||
$mem = (int)($mem / 1024);
|
||||
$mem >= $memoryLimit && posix_kill($pid, SIGINT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get memory limit
|
||||
* @param mixed $memoryLimit
|
||||
* @return float
|
||||
*/
|
||||
private static function _getMemoryLimit($memoryLimit): float
|
||||
{
|
||||
if ($memoryLimit === 0) {
|
||||
return floatval(0);
|
||||
}
|
||||
$usePhpIni = false;
|
||||
if (!$memoryLimit) {
|
||||
$usePhpIni = true;
|
||||
$memoryLimit = ini_get('memory_limit');
|
||||
}
|
||||
if ($memoryLimit == -1) return floatval(0);
|
||||
$unit = strtolower($memoryLimit[strlen($memoryLimit) - 1]);
|
||||
if ($unit === 'g') {
|
||||
$memoryLimit = 1024 * intval($memoryLimit);
|
||||
} else if ($unit === 'm') {
|
||||
$memoryLimit = intval($memoryLimit);
|
||||
} else if ($unit === 'k') {
|
||||
$memoryLimit = intval($memoryLimit / 1024);
|
||||
} else {
|
||||
$memoryLimit = intval($memoryLimit / 1024 / 1024);
|
||||
}
|
||||
if ($memoryLimit < 30) $memoryLimit = 30;
|
||||
if ($usePhpIni) $memoryLimit = (int)(0.8 * $memoryLimit);
|
||||
return floatval($memoryLimit);
|
||||
}
|
||||
}
|
||||
@ -116,11 +116,6 @@ class Worker extends Command
|
||||
if ('start' === $action) $output->writeln('Starting Workerman http server...');
|
||||
$worker = new HttpServer($host, $port, $this->config['context'] ?? [], $this->config['callable'] ?? null);
|
||||
$worker->setRoot($this->app->getRootPath());
|
||||
// 设置热更新监听文件后缀及目录
|
||||
if (empty($this->config['files']['exts'])) $this->config['files']['exts'] = ['*'];
|
||||
if (empty($this->config['files']['path'])) $this->config['files']['path'] = [$this->app->getBasePath(), $this->app->getConfigPath()];
|
||||
$worker->setMonitorChange(intval($this->config['files']['time'] ?? 0), $this->config['files']['path'], $this->config['files']['exts']);
|
||||
$worker->setMonitorMemory(intval($this->config['memory']['time'] ?? 0), $this->config['memory']['limit'] ?? null);
|
||||
} else {
|
||||
if (strtolower($this->config['type']) !== 'business') {
|
||||
if (empty($this->config['listen'])) {
|
||||
|
||||
@ -42,9 +42,6 @@ class HttpServer extends Server
|
||||
/** @var string */
|
||||
protected $root;
|
||||
|
||||
/** @var array */
|
||||
protected $monitor;
|
||||
|
||||
/** @var callable */
|
||||
protected $callable;
|
||||
|
||||
@ -79,12 +76,6 @@ class HttpServer extends Server
|
||||
class_alias(ThinkResponseFile::class, 'think\response\File');
|
||||
}
|
||||
|
||||
// 设置文件变化及内存超限监控管理
|
||||
if (0 == $worker->id && $this->monitor && Library::$sapp->isDebug()) {
|
||||
Monitor::enableChangeMonitor($this->monitor['change_path'] ?? [], $this->monitor['change_exts'] ?? ['*'], $this->monitor['change_time'] ?? 0);
|
||||
Monitor::enableMemoryMonitor($this->monitor['memory_limit'] ?? null, $this->monitor['memory_time'] ?? 0);
|
||||
}
|
||||
|
||||
// 初始化运行环境
|
||||
RuntimeService::init($this->app)->initialize();
|
||||
|
||||
@ -145,30 +136,4 @@ class HttpServer extends Server
|
||||
{
|
||||
$this->root = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文件监控配置
|
||||
* @param integer $time
|
||||
* @param array $path 监听目录
|
||||
* @param array $exts 文件后缀
|
||||
* @return void
|
||||
*/
|
||||
public function setMonitorChange(int $time = 2, array $path = [], array $exts = ['*'])
|
||||
{
|
||||
$this->monitor['change_path'] = $path;
|
||||
$this->monitor['change_exts'] = $exts;
|
||||
$this->monitor['change_time'] = $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内存监控配置
|
||||
* @param integer $time
|
||||
* @param ?string $limit
|
||||
* @return void
|
||||
*/
|
||||
public function setMonitorMemory(int $time = 60, ?string $limit = null)
|
||||
{
|
||||
$this->monitor['memory_time'] = $time;
|
||||
$this->monitor['memory_limit'] = $limit;
|
||||
}
|
||||
}
|
||||
@ -33,20 +33,4 @@ return [
|
||||
'name' => 'ThinkAdmin',
|
||||
'count' => 4,
|
||||
],
|
||||
// 监控文件变更重载,仅 Debug 模式有效
|
||||
'files' => [
|
||||
// 监控检测间隔(单位秒,零不监控)
|
||||
'time' => 3,
|
||||
// 文件监控目录(默认监控 app+config 目录)
|
||||
'path' => [],
|
||||
// 文件监控后缀(默认监控 所有 文件)
|
||||
'exts' => ['*']
|
||||
],
|
||||
// 监控内存超限重载,仅 Debug 模式有效
|
||||
'memory' => [
|
||||
// 监控检测间隔(单位秒,零不监控)
|
||||
'time' => 60,
|
||||
// 限制内存大小(可选单位有 G M K )
|
||||
'limit' => '1G'
|
||||
],
|
||||
];
|
||||
Loading…
x
Reference in New Issue
Block a user