mirror of
https://gitee.com/zoujingli/ThinkAdmin.git
synced 2026-06-12 22:28:15 +08:00
fix: 由于部分使用场景异常,去除文件动态监听与内存监控重启
This commit is contained in:
parent
056ade708f
commit
a85cdf49d8
@ -58,22 +58,6 @@ return [
|
|||||||
// 进程数量
|
// 进程数量
|
||||||
'count' => 4,
|
'count' => 4,
|
||||||
],
|
],
|
||||||
// 监控文件变更重载
|
|
||||||
'files' => [
|
|
||||||
// 监控检测间隔(单位秒,零不监控)
|
|
||||||
'time' => 3,
|
|
||||||
// 文件监控目录(默认监控 app+config 目录)
|
|
||||||
'path' => [],
|
|
||||||
// 文件监控后缀(默认监控 所有 文件)
|
|
||||||
'exts' => ['*']
|
|
||||||
],
|
|
||||||
// 监控内存超限重载
|
|
||||||
'memory' => [
|
|
||||||
// 监控检测间隔(单位秒,零不监控)
|
|
||||||
'time' => 60,
|
|
||||||
// 限制内存大小(可选单位有 G M K )
|
|
||||||
'limit' => '1G'
|
|
||||||
],
|
|
||||||
// 自定义服务配置(可选)
|
// 自定义服务配置(可选)
|
||||||
'customs' => [
|
'customs' => [
|
||||||
// 自定义 text 服务
|
// 自定义 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...');
|
if ('start' === $action) $output->writeln('Starting Workerman http server...');
|
||||||
$worker = new HttpServer($host, $port, $this->config['context'] ?? [], $this->config['callable'] ?? null);
|
$worker = new HttpServer($host, $port, $this->config['context'] ?? [], $this->config['callable'] ?? null);
|
||||||
$worker->setRoot($this->app->getRootPath());
|
$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 {
|
} else {
|
||||||
if (strtolower($this->config['type']) !== 'business') {
|
if (strtolower($this->config['type']) !== 'business') {
|
||||||
if (empty($this->config['listen'])) {
|
if (empty($this->config['listen'])) {
|
||||||
|
|||||||
@ -42,9 +42,6 @@ class HttpServer extends Server
|
|||||||
/** @var string */
|
/** @var string */
|
||||||
protected $root;
|
protected $root;
|
||||||
|
|
||||||
/** @var array */
|
|
||||||
protected $monitor;
|
|
||||||
|
|
||||||
/** @var callable */
|
/** @var callable */
|
||||||
protected $callable;
|
protected $callable;
|
||||||
|
|
||||||
@ -79,12 +76,6 @@ class HttpServer extends Server
|
|||||||
class_alias(ThinkResponseFile::class, 'think\response\File');
|
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();
|
RuntimeService::init($this->app)->initialize();
|
||||||
|
|
||||||
@ -145,30 +136,4 @@ class HttpServer extends Server
|
|||||||
{
|
{
|
||||||
$this->root = $path;
|
$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',
|
'name' => 'ThinkAdmin',
|
||||||
'count' => 4,
|
'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