add:新增监控模块
This commit is contained in:
parent
5211d29c5e
commit
c74c3c23d4
29
catch/monitor/MonitorService.php
Normal file
29
catch/monitor/MonitorService.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace catchAdmin\monitor;
|
||||||
|
|
||||||
|
use catcher\ModuleService;
|
||||||
|
|
||||||
|
class MonitorService extends ModuleService
|
||||||
|
{
|
||||||
|
public function loadRouteFrom()
|
||||||
|
{
|
||||||
|
// TODO: Implement loadRouteFrom() method.
|
||||||
|
return __DIR__ . DIRECTORY_SEPARATOR . 'route.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadCommands()
|
||||||
|
{
|
||||||
|
return [__NAMESPACE__, __DIR__ . DIRECTORY_SEPARATOR . 'command'];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
175
catch/monitor/command/CatchCrontabCommand.php
Normal file
175
catch/monitor/command/CatchCrontabCommand.php
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace catchAdmin\monitor\command;
|
||||||
|
|
||||||
|
use catchAdmin\monitor\command\process\Master;
|
||||||
|
use catchAdmin\monitor\command\process\Process;
|
||||||
|
use catcher\facade\FileSystem;
|
||||||
|
use think\console\Command;
|
||||||
|
use think\console\Input;
|
||||||
|
use think\console\input\Argument;
|
||||||
|
use think\console\input\Option;
|
||||||
|
use think\console\Output;
|
||||||
|
use think\console\Table;
|
||||||
|
|
||||||
|
class CatchCrontabCommand extends Command
|
||||||
|
{
|
||||||
|
protected $pid;
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
// 指令配置
|
||||||
|
$this->setName('catch:crontab')
|
||||||
|
->addArgument('action', Argument::OPTIONAL, '[start|reload|stop|restart]', 'start')
|
||||||
|
->addOption('daemon', '-d', Option::VALUE_NONE, 'daemon mode')
|
||||||
|
->addOption('pid', '-p', Option::VALUE_REQUIRED, 'you can send signal to the process of pid')
|
||||||
|
->addOption('static', '-s', Option::VALUE_REQUIRED, 'default static process number', 1)
|
||||||
|
->addOption('dynamic', '-dy', Option::VALUE_REQUIRED, 'default dynamic process number', 10)
|
||||||
|
->addOption('interval', '-i', Option::VALUE_REQUIRED, 'interval/seconds', 60)
|
||||||
|
->setDescription('start catch crontab schedule');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(Input $input, Output $output)
|
||||||
|
{
|
||||||
|
if (!$input->hasOption('pid')) {
|
||||||
|
$this->pid = Master::getMasterPid();
|
||||||
|
} else {
|
||||||
|
$this->pid = $input->getOption('pid');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!extension_loaded('pcntl') || !extension_loaded('posix')) {
|
||||||
|
$output->error('you should install extension [pcntl && posix]');
|
||||||
|
} else {
|
||||||
|
$this->{$input->getArgument('action')}();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进程启动
|
||||||
|
*
|
||||||
|
* @time 2020年09月14日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function start()
|
||||||
|
{
|
||||||
|
$worker = new Master();
|
||||||
|
|
||||||
|
$worker->staticNumber($this->input->getOption('static'))
|
||||||
|
->dynamic($this->input->getOption('dynamic'))
|
||||||
|
->interval($this->input->getOption('interval'))
|
||||||
|
->asDaemon($this->input->hasOption('daemon'))
|
||||||
|
->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止任务
|
||||||
|
*
|
||||||
|
* @time 2020年07月07日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function stop()
|
||||||
|
{
|
||||||
|
$retryTimes = 0;
|
||||||
|
|
||||||
|
if (Process::isAlive($this->pid)) {
|
||||||
|
$this->output->info('🔨 catch crontab is running.');
|
||||||
|
Process::kill($this->pid, SIGTERM);
|
||||||
|
// 睡眠 1 秒
|
||||||
|
$this->output->info('⌛️ killing catch crontab service, please waiting...');
|
||||||
|
sleep(1);
|
||||||
|
if (!Process::isAlive($this->pid)) {
|
||||||
|
$this->output->info('🎉 catch crontab stopped!');
|
||||||
|
} else {
|
||||||
|
while (true) {
|
||||||
|
Process::kill($this->pid, SIGKILL);
|
||||||
|
if (Process::isAlive($this->pid)) {
|
||||||
|
$retryTimes++;
|
||||||
|
$this->output->info('🔥 retry $retryTimes times');
|
||||||
|
usleep(500 * 1000);
|
||||||
|
if ($retryTimes >= 3) {
|
||||||
|
$this->output->info('💔 catch crontab is running, stop failed, please use [kill -9 {$this->pid}] to Stop it');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->output->info('🎉 catch crontab stopped!');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Master::exitMasterDo();
|
||||||
|
} else {
|
||||||
|
$this->output->error('🤔️ catch crontab is not running, Please Check it!');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->output->info('🎉 stop catch crontab successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重启任务
|
||||||
|
*
|
||||||
|
* @time 2020年07月07日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function reload()
|
||||||
|
{
|
||||||
|
Process::kill($this->pid, SIGUSR1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重启
|
||||||
|
*
|
||||||
|
* @time 2020年07月07日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function restart()
|
||||||
|
{
|
||||||
|
$this->stop();
|
||||||
|
|
||||||
|
$this->output->info('catch crontab restarting...');
|
||||||
|
|
||||||
|
usleep(500 * 1000);
|
||||||
|
|
||||||
|
$this->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* status
|
||||||
|
*
|
||||||
|
* @time 2020年07月22日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function status()
|
||||||
|
{
|
||||||
|
if ($this->pid) {
|
||||||
|
if (Process::isAlive($this->pid)) {
|
||||||
|
Process::kill($this->pid, SIGUSR2);
|
||||||
|
|
||||||
|
usleep(100000);
|
||||||
|
|
||||||
|
$worker = new Master;
|
||||||
|
$table = new Table;
|
||||||
|
|
||||||
|
$table->setHeader(['PID', '名称', '内存', '处理任务', '开始时间', '运行时间', '状态'], Table::ALIGN_CENTER);
|
||||||
|
|
||||||
|
$table->setRows($worker->getWorkerStatus(), Table::ALIGN_CENTER);
|
||||||
|
|
||||||
|
$this->output->info($table->render());
|
||||||
|
} else {
|
||||||
|
$this->output->error('🤔️ catch crontab is not running, Please Check it!');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->output->error('🤔️ catch crontab is not running, Please Check it!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
145
catch/monitor/command/process/Attributes.php
Normal file
145
catch/monitor/command/process/Attributes.php
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace catchAdmin\monitor\command\process;
|
||||||
|
|
||||||
|
use catcher\base\CatchCronTask;
|
||||||
|
|
||||||
|
trait Attributes
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 是否以守护进程方式运行
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $daemon = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静态进程数量
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $static;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态进程数量
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $dynamic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时器触发时间
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $interval;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set name
|
||||||
|
*
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
protected $name = 'catch-crontab';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $crontabQueueName = 'catch-crontab-task';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全退出
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $exitSafely = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置守护进程
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @param bool $daemon
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function asDaemon($daemon = false)
|
||||||
|
{
|
||||||
|
$this->daemon = $daemon;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function staticNumber($n)
|
||||||
|
{
|
||||||
|
$this->static = $n;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 可扩容
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @param $n
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function dynamic($n)
|
||||||
|
{
|
||||||
|
$this->dynamic = $n;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @param $n
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function interval($n)
|
||||||
|
{
|
||||||
|
$this->interval = $n;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 name
|
||||||
|
*
|
||||||
|
* @time 2020年07月23日
|
||||||
|
* @param $name
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function name($name)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置报告错误
|
||||||
|
*
|
||||||
|
* @time 2020年07月24日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function displayErrors()
|
||||||
|
{
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
|
||||||
|
error_reporting(E_ALL & ~E_WARNING);
|
||||||
|
|
||||||
|
ini_set('display_startup_errors', 1);
|
||||||
|
|
||||||
|
ini_set('ignore_repeated_errors', 1);
|
||||||
|
}
|
||||||
|
}
|
361
catch/monitor/command/process/Master.php
Normal file
361
catch/monitor/command/process/Master.php
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace catchAdmin\monitor\command\process;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use catcher\facade\Filesystem;
|
||||||
|
use think\cache\driver\Redis;
|
||||||
|
use think\facade\Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* - 以后台形式工作 daemon
|
||||||
|
* - 分静态进程和动态扩容进程
|
||||||
|
* - 信号处理机制
|
||||||
|
* - 重启工作进程
|
||||||
|
* - 重启服务
|
||||||
|
* - 定时器 扩容工作进程
|
||||||
|
* - 关闭进程
|
||||||
|
* - 统计信息
|
||||||
|
* - 是否拉起进程,工作进程销毁后是否继续主进程保留
|
||||||
|
* - Fatal Error 处理
|
||||||
|
* - Exception 处理
|
||||||
|
* - 发生内存泄漏如何处理
|
||||||
|
* - 错误输出到哪里
|
||||||
|
* - 提供基础面板查看
|
||||||
|
* - Log 文件的记录
|
||||||
|
*
|
||||||
|
* @time 2020年07月29日
|
||||||
|
*/
|
||||||
|
class Master
|
||||||
|
{
|
||||||
|
use RegisterSignal, Attributes, Store, ParseTask;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存子进程 PID
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $workerIds = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始时间
|
||||||
|
*
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
public $start_at;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
public $worker_start_at;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存当前工作进程的数量
|
||||||
|
*
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
protected $allWorkersCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存当前重定向输出文件
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected static $stdout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务对象
|
||||||
|
*
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
protected $taskService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理的任务数量
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $dealNum = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* busy waiting
|
||||||
|
*
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
protected $status = 'waiting';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
protected $redis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if ($this->daemon) {
|
||||||
|
Process::daemon();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->interval) {
|
||||||
|
Process::alarm($this->interval);
|
||||||
|
}
|
||||||
|
$this->init();
|
||||||
|
// 初始化进程池
|
||||||
|
$this->initWorkers();
|
||||||
|
// 设置进程名称
|
||||||
|
Process::setWorkerName($this->name . ' master');
|
||||||
|
// 注册信号
|
||||||
|
$this->registerSignal();
|
||||||
|
// 写入进程状态
|
||||||
|
$this->setWorkerStatus($this->name . ' master');
|
||||||
|
// 信号发送
|
||||||
|
while (true) {
|
||||||
|
Process::dispatch();
|
||||||
|
$pid = pcntl_waitpid(-1, $status, WNOHANG);
|
||||||
|
Process::dispatch();
|
||||||
|
if ($pid > 0) {
|
||||||
|
if (isset($this->workerIds[$pid])) {
|
||||||
|
unset($this->workerIds[$pid]);
|
||||||
|
$this->deleteWorkerStatusFile($pid);
|
||||||
|
$this->worker_start_at = time();
|
||||||
|
// 如果进程挂掉,正常退出码都是 0,当然这里可以自己定义,看 exit($status) 设置什么
|
||||||
|
// 真实的 exit code pcntl_wexitstatus 函数获取
|
||||||
|
// exit code > 0 都是由于异常导致的
|
||||||
|
$exitCode = pcntl_wexitstatus($status);
|
||||||
|
if (!in_array($exitCode, [255, 250])) {
|
||||||
|
$this->forkStatic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果静态工作进程全部退出,会发生 CPU 空转,所以这里需要 sleep 1
|
||||||
|
if (!count($this->workerIds)) {
|
||||||
|
// sleep(1);
|
||||||
|
self::exitMasterDo();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(500 * 1000);
|
||||||
|
}
|
||||||
|
} catch (\Throwable $exception) {
|
||||||
|
// todo
|
||||||
|
echo $exception->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function init()
|
||||||
|
{
|
||||||
|
$this->displayErrors();
|
||||||
|
$this->start_at = $this->worker_start_at = time();
|
||||||
|
// 记录 masterID
|
||||||
|
FileSystem::put(self::masterPidStorePath(), posix_getpid());
|
||||||
|
// 保存信息
|
||||||
|
$this->saveTaskInfo();
|
||||||
|
// 初始化进程数量
|
||||||
|
$this->allWorkersCount = $this->static;
|
||||||
|
// 显示UI
|
||||||
|
$this->display();
|
||||||
|
// 重定向
|
||||||
|
$this->dup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化进程池
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function initWorkers()
|
||||||
|
{
|
||||||
|
$this->redis = $this->getRedisHandle();
|
||||||
|
|
||||||
|
for ($i = 0; $i < $this->static; $i++) {
|
||||||
|
$this->forkStatic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fork 进程
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function forkDynamic()
|
||||||
|
{
|
||||||
|
$process = new Process(function (Process $process) {
|
||||||
|
$redis = $this->getRedisHandle();
|
||||||
|
while($crontab = $redis->rpop($this->crontabQueueName)) {
|
||||||
|
$task = $this->getTaskObject(\json_decode($crontab, true));
|
||||||
|
$task->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
$process->exit();
|
||||||
|
});
|
||||||
|
|
||||||
|
$process->start();
|
||||||
|
|
||||||
|
$this->workerIds[$process->pid] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静态进程
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function forkStatic()
|
||||||
|
{
|
||||||
|
$process = new Process(function (Process $process) {
|
||||||
|
$process->initMemory();
|
||||||
|
|
||||||
|
$name = $this->name . ' worker';
|
||||||
|
$this->setWorkerStatus($name, $this->dealNum, $this->status);
|
||||||
|
|
||||||
|
Process::setWorkerName($name);
|
||||||
|
|
||||||
|
Process::signal(SIGUSR2, function ($signal) use ($name) {
|
||||||
|
$this->setWorkerStatus($name, $this->dealNum, $this->status);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 该信号保证进程完成任务后安全退出
|
||||||
|
Process::signal(SIGTERM, function ($signal) {
|
||||||
|
$this->exitSafely = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
/************** 任务 *********************/
|
||||||
|
$this->status = 'busying';
|
||||||
|
$this->setWorkerStatus($name, $this->dealNum, 'busying');
|
||||||
|
|
||||||
|
// 处理定时任务
|
||||||
|
while ($crontab = $this->redis->rpop($this->crontabQueueName)) {
|
||||||
|
$task = $this->getTaskObject(\json_decode($crontab, true));
|
||||||
|
$task->run();
|
||||||
|
if ($task->shouldExit()) {
|
||||||
|
$process->exit(250);
|
||||||
|
}
|
||||||
|
$this->dealNum += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->status = 'waiting';
|
||||||
|
$this->setWorkerStatus($name, $this->dealNum, 'waiting');
|
||||||
|
/****************处理*********************/
|
||||||
|
// 暂停一秒 让出CPU调度
|
||||||
|
sleep(1);
|
||||||
|
// 信号调度
|
||||||
|
Process::dispatch();
|
||||||
|
// 是否需要安全退出 || 查看内存是否溢出
|
||||||
|
if ($this->exitSafely || $process->isMemoryOverflow()) {
|
||||||
|
$process->exit();
|
||||||
|
//exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$process->start();
|
||||||
|
|
||||||
|
$this->workerIds[$process->pid] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重定向文件流
|
||||||
|
*
|
||||||
|
* @time 2020年07月22日
|
||||||
|
* @return void
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function dup()
|
||||||
|
{
|
||||||
|
if (!$this->daemon) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
global $stdout, $stderr;
|
||||||
|
|
||||||
|
// 关闭标准输入输出
|
||||||
|
fclose(STDOUT);
|
||||||
|
fclose(STDIN);
|
||||||
|
fclose(STDERR);
|
||||||
|
|
||||||
|
// 重定向输出&错误
|
||||||
|
$stdoutPath = self::$stdout ?: self::stdoutPath();
|
||||||
|
|
||||||
|
!file_exists($stdoutPath) && touch($stdoutPath);
|
||||||
|
// 等待 100 毫秒
|
||||||
|
usleep(100 * 1000);
|
||||||
|
|
||||||
|
$stdout = fopen($stdoutPath, 'a');
|
||||||
|
|
||||||
|
$stderr = fopen($stdoutPath, 'a');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 输出
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function output()
|
||||||
|
{
|
||||||
|
$isShowCtrlC = $this->daemon ? '' : 'Ctrl+c to stop' . "\r\n";
|
||||||
|
|
||||||
|
$info = <<<EOT
|
||||||
|
---------------------------------------------------------------- 🚀
|
||||||
|
| _ _ _ _ |
|
||||||
|
| | | | | | | | | |
|
||||||
|
| ___ __ _| |_ ___| |__ ___ _ __ ___ _ __ | |_ __ _| |__ |
|
||||||
|
| / __/ _` | __/ __| '_ \ / __| '__/ _ \| '_ \| __/ _` | '_ \ |
|
||||||
|
| | (_| (_| | || (__| | | | | (__| | | (_) | | | | || (_| | |_) ||
|
||||||
|
| \___\__,_|\__\___|_| |_| \___|_| \___/|_| |_|\__\__,_|_.__/ |
|
||||||
|
| | |
|
||||||
|
|----------------------------------------------------------------|
|
||||||
|
$isShowCtrlC
|
||||||
|
EOT;
|
||||||
|
return file_put_contents(self::statusPath(), $info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示
|
||||||
|
*
|
||||||
|
* @time 2020年07月22日
|
||||||
|
* @return false|int
|
||||||
|
*/
|
||||||
|
protected function display()
|
||||||
|
{
|
||||||
|
$this->output();
|
||||||
|
|
||||||
|
return fwrite(STDOUT, $this->renderStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 redis 句柄
|
||||||
|
*
|
||||||
|
* @time 2020年09月15日
|
||||||
|
* @return object|null
|
||||||
|
*/
|
||||||
|
protected function getRedisHandle()
|
||||||
|
{
|
||||||
|
return Cache::store('redis')->handler();
|
||||||
|
}
|
||||||
|
}
|
47
catch/monitor/command/process/ParseTask.php
Normal file
47
catch/monitor/command/process/ParseTask.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
namespace catchAdmin\monitor\command\process;
|
||||||
|
|
||||||
|
use catcher\facade\FileSystem;
|
||||||
|
use think\exception\ClassNotFoundException;
|
||||||
|
use think\helper\Str;
|
||||||
|
|
||||||
|
trait ParseTask
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 获取任务
|
||||||
|
*
|
||||||
|
* @time 2020年09月15日
|
||||||
|
* @param $crontab
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
protected function getTaskObject($crontab)
|
||||||
|
{
|
||||||
|
$class = $this->getTaskNamespace() . ucfirst(Str::camel($crontab['task']));
|
||||||
|
|
||||||
|
if (class_exists($class)) {
|
||||||
|
return app()->make($class)->setCrontab($crontab);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ClassNotFoundException('Task '. $crontab['task'] . ' not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取任务命名空间
|
||||||
|
*
|
||||||
|
* @time 2020年09月15日
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
protected function getTaskNamespace()
|
||||||
|
{
|
||||||
|
return config('catch.crontab.task_namespace');
|
||||||
|
}
|
||||||
|
}
|
213
catch/monitor/command/process/Process.php
Normal file
213
catch/monitor/command/process/Process.php
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace catchAdmin\monitor\command\process;
|
||||||
|
|
||||||
|
use catcher\exceptions\FailedException;
|
||||||
|
|
||||||
|
class Process
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 保存工作进程 PID
|
||||||
|
*
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
public $pid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户自定义方法
|
||||||
|
*
|
||||||
|
* @var callable
|
||||||
|
*/
|
||||||
|
protected $callable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请最大内存 给出缓冲期
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $initMemory = '256M';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 超过最大内存报警
|
||||||
|
*
|
||||||
|
* @var float|int
|
||||||
|
*/
|
||||||
|
protected $allowMaxMemory = 128 * 1024 * 1024;
|
||||||
|
|
||||||
|
public function __construct(callable $callable)
|
||||||
|
{
|
||||||
|
$this->callable = $callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 守护进程
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @return void
|
||||||
|
* @throws FailedException
|
||||||
|
*/
|
||||||
|
public static function daemon()
|
||||||
|
{
|
||||||
|
$pid = pcntl_fork();
|
||||||
|
|
||||||
|
if ($pid < 0) {
|
||||||
|
throw new FailedException('fork process failed');
|
||||||
|
}
|
||||||
|
// 退出父进程
|
||||||
|
if ($pid > 0) {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
// 设置新的会话组
|
||||||
|
if (posix_setsid() < 0) {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
chdir('/');
|
||||||
|
// 重置掩码 权限问题
|
||||||
|
umask(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动进程
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function start()
|
||||||
|
{
|
||||||
|
$pid = pcntl_fork();
|
||||||
|
|
||||||
|
if ($this->pid < 0) {
|
||||||
|
exit('fork failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($pid > 0) {
|
||||||
|
$this->pid = $pid;
|
||||||
|
} else {
|
||||||
|
call_user_func_array($this->callable, [$this]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 信号
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @param $signal
|
||||||
|
* @param $callable
|
||||||
|
* @param $restartSysCalls
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function signal($signal, $callable, $restartSysCalls = false)
|
||||||
|
{
|
||||||
|
pcntl_signal($signal, $callable, $restartSysCalls);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default 1 second
|
||||||
|
*
|
||||||
|
* @param $interval
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public static function alarm($interval = 1)
|
||||||
|
{
|
||||||
|
return pcntl_alarm($interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* linux 进程下设置进程名称
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @param $title
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function setWorkerName($title)
|
||||||
|
{
|
||||||
|
if (strtolower(PHP_OS) === 'linux') {
|
||||||
|
cli_set_process_title($title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全退出
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @param int $status
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function exit($status = 0)
|
||||||
|
{
|
||||||
|
exit($status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* kill
|
||||||
|
*
|
||||||
|
* @time 2020年07月22日
|
||||||
|
* @param $pid
|
||||||
|
* @param $signal
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function kill($pid, $signal)
|
||||||
|
{
|
||||||
|
return posix_kill($pid, $signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @time 2020年07月22日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function dispatch()
|
||||||
|
{
|
||||||
|
pcntl_signal_dispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否存活
|
||||||
|
*
|
||||||
|
* @time 2020年07月22日
|
||||||
|
* @param $pid
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isAlive($pid)
|
||||||
|
{
|
||||||
|
return posix_kill($pid, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化进程内存
|
||||||
|
*
|
||||||
|
* @time 2020年07月22日
|
||||||
|
* @param int $memory
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function initMemory($memory = 0)
|
||||||
|
{
|
||||||
|
if (ini_get('memory_limit') != $this->initMemory) {
|
||||||
|
// 这里申请一块稍微大的内存
|
||||||
|
ini_set('memory_limit', $memory ?: $this->initMemory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否超过最大内存
|
||||||
|
*
|
||||||
|
* @time 2020年07月22日
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function isMemoryOverflow()
|
||||||
|
{
|
||||||
|
// 一旦超过了允许的内存 直接退出进程
|
||||||
|
return memory_get_usage() > $this->allowMaxMemory;
|
||||||
|
}
|
||||||
|
}
|
156
catch/monitor/command/process/RegisterSignal.php
Normal file
156
catch/monitor/command/process/RegisterSignal.php
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace catchAdmin\monitor\command\process;
|
||||||
|
|
||||||
|
use catchAdmin\monitor\model\Crontab;
|
||||||
|
use catcher\facade\FileSystem;
|
||||||
|
use Cron\CronExpression;
|
||||||
|
use EasyWeChat\Kernel\Messages\News;
|
||||||
|
use think\cache\driver\Redis;
|
||||||
|
|
||||||
|
trait RegisterSignal
|
||||||
|
{
|
||||||
|
public function registerSignal()
|
||||||
|
{
|
||||||
|
// 退出信号
|
||||||
|
$this->exit();
|
||||||
|
// 等待子进程退出
|
||||||
|
$this->waitWorkersExit();
|
||||||
|
// 动态扩容
|
||||||
|
$this->workerChecked();
|
||||||
|
// 重启进程
|
||||||
|
$this->reload();
|
||||||
|
// 统计信息
|
||||||
|
$this->showStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进程退出
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function exit()
|
||||||
|
{
|
||||||
|
Process::signal(SIGTERM, function ($signal) {
|
||||||
|
foreach ($this->workerIds as $pid => $v) {
|
||||||
|
if (isset($this->workerIds[$pid])) {
|
||||||
|
unset($this->workerIds[$pid]);
|
||||||
|
}
|
||||||
|
Process::kill($pid, SIGTERM);
|
||||||
|
}
|
||||||
|
Process::kill(self::getMasterPid(), SIGKILL);
|
||||||
|
});
|
||||||
|
|
||||||
|
Process::signal(SIGINT, function ($signal) {
|
||||||
|
foreach ($this->workerIds as $pid => $v) {
|
||||||
|
if (isset($this->workerIds[$pid])) {
|
||||||
|
unset($this->workerIds[$pid]);
|
||||||
|
}
|
||||||
|
Process::kill($pid, SIGKILL);
|
||||||
|
}
|
||||||
|
Process::kill(self::getMasterPid(), SIGKILL);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子进程退出
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function waitWorkersExit()
|
||||||
|
{
|
||||||
|
Process::signal(SIGCHLD, function ($signal) {
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进程检测
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function workerChecked()
|
||||||
|
{
|
||||||
|
Process::signal(SIGALRM, function ($signal) {
|
||||||
|
$process = new Process(function (Process $process) {
|
||||||
|
$crontabs = Crontab::where('status', Crontab::ENABLE)
|
||||||
|
->where('tactics', '<>', Crontab::EXECUTE_FORBIDDEN)
|
||||||
|
->select()->toArray();
|
||||||
|
// 任务
|
||||||
|
foreach ($crontabs as $crontab) {
|
||||||
|
$can = CronExpression::factory(trim($crontab['cron']))
|
||||||
|
->getNextRunDate(date('Y-m-d H:i:s'), 0 , true)
|
||||||
|
->getTimestamp() == time();
|
||||||
|
if ($can) {
|
||||||
|
// 如果任务只执行一次 之后禁用该任务
|
||||||
|
if ($crontab['tactics'] === Crontab::EXECUTE_ONCE) {
|
||||||
|
Crontab::where('id', $crontab['id'])->update([
|
||||||
|
'status' => Crontab::DISABLE,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$redis = $this->getRedisHandle();
|
||||||
|
|
||||||
|
$redis->lpush($this->crontabQueueName, json_encode([
|
||||||
|
'id' => $crontab['id'],
|
||||||
|
'task' => $crontab['task'],
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$process->exit();
|
||||||
|
});
|
||||||
|
|
||||||
|
$process->start();
|
||||||
|
|
||||||
|
Process::alarm($this->interval);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重启
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function reload()
|
||||||
|
{
|
||||||
|
Process::signal(SIGUSR1, function ($signal) {
|
||||||
|
$this->worker_start_at = 0;
|
||||||
|
foreach ($this->workerIds as $pid => $v) {
|
||||||
|
Process::kill($pid, SIGTERM);
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预留信号
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function showStatus()
|
||||||
|
{
|
||||||
|
Process::signal(SIGUSR2, function ($signal) {
|
||||||
|
$this->setWorkerStatus($this->name . ' master');
|
||||||
|
foreach ($this->workerIds as $pid => $v) {
|
||||||
|
Process::kill($pid, SIGUSR2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
243
catch/monitor/command/process/Store.php
Normal file
243
catch/monitor/command/process/Store.php
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace catchAdmin\monitor\command\process;
|
||||||
|
|
||||||
|
use catcher\facade\FileSystem;
|
||||||
|
|
||||||
|
trait Store
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* worker 根目录
|
||||||
|
*
|
||||||
|
* @time 2020年07月23日
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function storeTaskPath()
|
||||||
|
{
|
||||||
|
$path = config('catch.crontab.store_path');
|
||||||
|
|
||||||
|
if (!Filesystem::exists($path)) {
|
||||||
|
FileSystem::makeDirectory($path, 0777, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存信息备用
|
||||||
|
*
|
||||||
|
* @time 2020年07月29日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function saveTaskInfo()
|
||||||
|
{
|
||||||
|
FileSystem::put(self::storeTaskPath() . 'information.json', \json_encode([
|
||||||
|
'name' => $this->name,
|
||||||
|
'static' => $this->static,
|
||||||
|
'dynamic' => $this->dynamic,
|
||||||
|
'interval' => $this->interval,
|
||||||
|
], JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* worker master pid
|
||||||
|
*
|
||||||
|
* @time 2020年07月23日
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function masterPidStorePath()
|
||||||
|
{
|
||||||
|
return self::storeTaskPath() . 'master.pid';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* worker master status
|
||||||
|
*
|
||||||
|
* @time 2020年07月23日
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function statusPath()
|
||||||
|
{
|
||||||
|
return self::storeTaskPath() . 'master.status';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* worker status
|
||||||
|
*
|
||||||
|
* @time 2020年07月23日
|
||||||
|
* @param string $name
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function workerStatusPath($name)
|
||||||
|
{
|
||||||
|
$path = self::storeTaskPath() . 'status/';
|
||||||
|
|
||||||
|
if (!FileSystem::exists($path)) {
|
||||||
|
FileSystem::makeDirectory($path, 0777, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $path . $name . '.status';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @time 2020年07月23日
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getWorkerStatusPath()
|
||||||
|
{
|
||||||
|
return self::storeTaskPath() . 'status/';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* worker log
|
||||||
|
*
|
||||||
|
* @time 2020年07月23日
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function stdoutPath()
|
||||||
|
{
|
||||||
|
return self::storeTaskPath() . 'errors.log';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 master pid
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @return false|string
|
||||||
|
*/
|
||||||
|
public static function getMasterPid()
|
||||||
|
{
|
||||||
|
$pidFile = config('catch.crontab.master_pid_file');
|
||||||
|
|
||||||
|
if (!file_exists($pidFile)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FileSystem::sharedGet($pidFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* status
|
||||||
|
*
|
||||||
|
* @time 2020年07月21日
|
||||||
|
* @return false|string
|
||||||
|
*/
|
||||||
|
public function renderStatus()
|
||||||
|
{
|
||||||
|
return file_get_contents(self::statusPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行时间
|
||||||
|
*
|
||||||
|
* @time 2020年07月23日
|
||||||
|
* @param $runtime
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getRunningTime($runtime)
|
||||||
|
{
|
||||||
|
$day = 3600 * 24;
|
||||||
|
if ($runtime > $day) {
|
||||||
|
$days = floor($runtime / $day);
|
||||||
|
return $days . '天:' . gmstrftime('%H:%M:%S', $runtime % $day);
|
||||||
|
} else {
|
||||||
|
return gmstrftime('%H:%M:%S', $runtime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取工作进程
|
||||||
|
*
|
||||||
|
* @time 2020年07月23日
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getWorkerStatus()
|
||||||
|
{
|
||||||
|
usleep(500 * 1000);
|
||||||
|
|
||||||
|
$files = FileSystem::glob(self::storeTaskPath() . 'status/*.status');
|
||||||
|
|
||||||
|
$workerStatus = [];
|
||||||
|
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$workerStatus[] = explode("\t", FileSystem::sharedGet($file));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $workerStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置进程状态
|
||||||
|
*
|
||||||
|
* @time 2020年07月23日
|
||||||
|
* @param $name
|
||||||
|
* @param int $dealNum
|
||||||
|
* @param string $status
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function setWorkerStatus($name, $dealNum = 0, $status = 'running')
|
||||||
|
{
|
||||||
|
$startAt = strpos($name, 'worker') ? $this->worker_start_at : $this->start_at;
|
||||||
|
|
||||||
|
if ($this->daemon) {
|
||||||
|
FileSystem::put($this->workerStatusPath($this->workerStatusFileName($name)), implode("\t", [
|
||||||
|
posix_getpid(),
|
||||||
|
$name,
|
||||||
|
floor(memory_get_usage() / 1024 / 1024) . 'M',
|
||||||
|
$dealNum,
|
||||||
|
date('Y-m-d H:i:s', $startAt),
|
||||||
|
$this->getRunningTime(time() - $startAt),
|
||||||
|
$status
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进程名称
|
||||||
|
*
|
||||||
|
* @time 2020年09月15日
|
||||||
|
* @param $name
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function workerStatusFileName($name)
|
||||||
|
{
|
||||||
|
return $name . '_' . posix_getpid();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除进程状态文件
|
||||||
|
*
|
||||||
|
* @time 2020年09月15日
|
||||||
|
* @param $pid
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function deleteWorkerStatusFile($pid)
|
||||||
|
{
|
||||||
|
@unlink(self::workerStatusPath($this->name . ' worker_' . $pid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出
|
||||||
|
*
|
||||||
|
* @time 2020年09月15日
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function exitMasterDo()
|
||||||
|
{
|
||||||
|
@unlink(self::masterPidStorePath());
|
||||||
|
@unlink(self::statusPath());
|
||||||
|
Filesystem::deleteDirectory(self::getWorkerStatusPath());
|
||||||
|
}
|
||||||
|
}
|
105
catch/monitor/controller/Crontab.php
Normal file
105
catch/monitor/controller/Crontab.php
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace catchAdmin\monitor\controller;
|
||||||
|
|
||||||
|
use catcher\base\CatchRequest as Request;
|
||||||
|
use catcher\CatchResponse;
|
||||||
|
use catcher\base\CatchController;
|
||||||
|
use catchAdmin\monitor\model\Crontab as CrontabModel;
|
||||||
|
use Cron\CronExpression;
|
||||||
|
|
||||||
|
class Crontab extends CatchController
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
|
||||||
|
public function __construct(CrontabModel $model)
|
||||||
|
{
|
||||||
|
$this->model = $model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表
|
||||||
|
*
|
||||||
|
* @time 2020/09/14 20:35
|
||||||
|
*
|
||||||
|
* @return \think\Response
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return CatchResponse::paginate($this->model->getList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存
|
||||||
|
*
|
||||||
|
* @time 2020/09/14 20:35
|
||||||
|
* @param Request Request
|
||||||
|
* @return \think\Response
|
||||||
|
*/
|
||||||
|
public function save(Request $request)
|
||||||
|
{
|
||||||
|
CronExpression::factory($request->post('cron'));
|
||||||
|
|
||||||
|
return CatchResponse::success($this->model->storeBy($request->post()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取
|
||||||
|
*
|
||||||
|
* @time 2020/09/14 20:35
|
||||||
|
* @param $id
|
||||||
|
* @return \think\Response
|
||||||
|
*/
|
||||||
|
public function read($id)
|
||||||
|
{
|
||||||
|
return CatchResponse::success($this->model->findBy($id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新
|
||||||
|
*
|
||||||
|
* @time 2020/09/14 20:35
|
||||||
|
* @param Request $request
|
||||||
|
* @return \think\Response
|
||||||
|
*/
|
||||||
|
public function update(Request $request, $id)
|
||||||
|
{
|
||||||
|
CronExpression::factory($request->post('cron'));
|
||||||
|
|
||||||
|
return CatchResponse::success($this->model->updateBy($id, $request->post()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*
|
||||||
|
* @time 2020/09/14 20:35
|
||||||
|
* @param $id
|
||||||
|
* @return \think\Response
|
||||||
|
*/
|
||||||
|
public function delete($id)
|
||||||
|
{
|
||||||
|
return CatchResponse::success($this->model->deleteBy($id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用启用
|
||||||
|
*
|
||||||
|
* @time 2020年09月15日
|
||||||
|
* @param $id
|
||||||
|
* @return \think\response\Json
|
||||||
|
*/
|
||||||
|
public function disOrEnable($id)
|
||||||
|
{
|
||||||
|
return CatchResponse::success($this->model->disOrEnable($id));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
50
catch/monitor/controller/CrontabLog.php
Normal file
50
catch/monitor/controller/CrontabLog.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
namespace catchAdmin\monitor\controller;
|
||||||
|
|
||||||
|
use catchAdmin\monitor\model\CrontabLog as LogModel;
|
||||||
|
use catcher\base\CatchController;
|
||||||
|
use catcher\CatchResponse;
|
||||||
|
use think\Request;
|
||||||
|
|
||||||
|
class CrontabLog extends CatchController
|
||||||
|
{
|
||||||
|
protected $model;
|
||||||
|
|
||||||
|
public function __construct(LogModel $model)
|
||||||
|
{
|
||||||
|
$this->model = $model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志列表
|
||||||
|
*
|
||||||
|
* @time 2020年09月15日
|
||||||
|
* @throws \think\db\exception\DbException
|
||||||
|
* @return \think\response\Json
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return CatchResponse::paginate($this->model->getList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除日志
|
||||||
|
*
|
||||||
|
* @time 2020年09月15日
|
||||||
|
* @param $id
|
||||||
|
* @return \think\response\Json
|
||||||
|
*/
|
||||||
|
public function delete($id)
|
||||||
|
{
|
||||||
|
return CatchResponse::success($this->model->deleteBy($id));
|
||||||
|
}
|
||||||
|
}
|
46
catch/monitor/database/migrations/20200914203553_crontab.php
Normal file
46
catch/monitor/database/migrations/20200914203553_crontab.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use think\migration\Migrator;
|
||||||
|
use think\migration\db\Column;
|
||||||
|
use Phinx\Db\Adapter\MysqlAdapter;
|
||||||
|
|
||||||
|
class Crontab extends Migrator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Change Method.
|
||||||
|
*
|
||||||
|
* Write your reversible migrations using this method.
|
||||||
|
*
|
||||||
|
* More information on writing migrations is available here:
|
||||||
|
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
|
||||||
|
*
|
||||||
|
* The following commands can be used in this method and Phinx will
|
||||||
|
* automatically reverse them when rolling back:
|
||||||
|
*
|
||||||
|
* createTable
|
||||||
|
* renameTable
|
||||||
|
* addColumn
|
||||||
|
* renameColumn
|
||||||
|
* addIndex
|
||||||
|
* addForeignKey
|
||||||
|
*
|
||||||
|
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||||
|
* with the Table class.
|
||||||
|
*/
|
||||||
|
public function change()
|
||||||
|
{
|
||||||
|
$table = $this->table('crontab', ['engine' => 'InnoDB', 'collation' => 'utf8mb4_general_ci', 'comment' => '定时任务' ,'id' => 'id','signed' => true ,'primary_key' => ['id']]);
|
||||||
|
$table->addColumn('name', 'string', ['limit' => 255,'null' => false,'default' => '','signed' => false,'comment' => '任务名称',])
|
||||||
|
->addColumn('group', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 默认 2 系统',])
|
||||||
|
->addColumn('task', 'string', ['limit' => 255,'null' => false,'default' => '','signed' => false,'comment' => '任务名称',])
|
||||||
|
->addColumn('cron', 'string', ['limit' => 50,'null' => false,'default' => '','signed' => false,'comment' => 'cron 表达式',])
|
||||||
|
->addColumn('tactics', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 立即执行 2 执行一次 3 放弃执行',])
|
||||||
|
->addColumn('status', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 正常 2 禁用',])
|
||||||
|
->addColumn('remark', 'string', ['limit' => 1000,'null' => false,'default' => '','signed' => false,'comment' => '备注',])
|
||||||
|
->addColumn('creator_id', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '创建人ID',])
|
||||||
|
->addColumn('created_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '创建时间',])
|
||||||
|
->addColumn('updated_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '更新时间',])
|
||||||
|
->addColumn('deleted_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '软删除',])
|
||||||
|
->create();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
use think\migration\Migrator;
|
||||||
|
use think\migration\db\Column;
|
||||||
|
use Phinx\Db\Adapter\MysqlAdapter;
|
||||||
|
|
||||||
|
class CrontabLog extends Migrator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Change Method.
|
||||||
|
*
|
||||||
|
* Write your reversible migrations using this method.
|
||||||
|
*
|
||||||
|
* More information on writing migrations is available here:
|
||||||
|
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
|
||||||
|
*
|
||||||
|
* The following commands can be used in this method and Phinx will
|
||||||
|
* automatically reverse them when rolling back:
|
||||||
|
*
|
||||||
|
* createTable
|
||||||
|
* renameTable
|
||||||
|
* addColumn
|
||||||
|
* renameColumn
|
||||||
|
* addIndex
|
||||||
|
* addForeignKey
|
||||||
|
*
|
||||||
|
* Remember to call "create()" or "update()" and NOT "save()" when working
|
||||||
|
* with the Table class.
|
||||||
|
*/
|
||||||
|
public function change()
|
||||||
|
{
|
||||||
|
$table = $this->table('crontab_log', ['engine' => 'Myisam', 'collation' => 'utf8mb4_general_ci', 'comment' => '定时任务日志' ,'id' => 'id','signed' => true ,'primary_key' => ['id']]);
|
||||||
|
$table->addColumn('crontab_id', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => 'crontab 任务ID',])
|
||||||
|
->addColumn('used_time', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '任务消耗时间',])
|
||||||
|
->addColumn('status', 'boolean', ['null' => false,'default' => 1,'signed' => false,'comment' => '1 成功 2 失败',])
|
||||||
|
->addColumn('error_message', 'string', ['limit' => 1000,'null' => false,'default' => '','signed' => false,'comment' => '错误信息',])
|
||||||
|
->addColumn('created_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '创建时间',])
|
||||||
|
->addColumn('updated_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '更新时间',])
|
||||||
|
->addColumn('deleted_at', 'integer', ['limit' => MysqlAdapter::INT_REGULAR,'null' => false,'default' => 0,'signed' => true,'comment' => '软删除',])
|
||||||
|
->create();
|
||||||
|
}
|
||||||
|
}
|
43
catch/monitor/model/Crontab.php
Normal file
43
catch/monitor/model/Crontab.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace catchAdmin\monitor\model;
|
||||||
|
|
||||||
|
use catchAdmin\monitor\model\search\CrontabSearch;
|
||||||
|
use catcher\base\CatchModel as Model;
|
||||||
|
|
||||||
|
class Crontab extends Model
|
||||||
|
{
|
||||||
|
use CrontabSearch;
|
||||||
|
|
||||||
|
protected $name = 'crontab';
|
||||||
|
|
||||||
|
protected $field = [
|
||||||
|
'id', //
|
||||||
|
'name', // 任务名称
|
||||||
|
'group', // 1 默认 2 系统
|
||||||
|
'task', // 任务名称
|
||||||
|
'cron', // cron 表达式
|
||||||
|
'tactics', // 1 立即执行 2 执行一次 3 放弃执行
|
||||||
|
'status', // 1 正常 2 禁用
|
||||||
|
'remark', // 备注
|
||||||
|
'creator_id', // 创建人ID
|
||||||
|
'created_at', // 创建时间
|
||||||
|
'updated_at', // 更新时间
|
||||||
|
'deleted_at', // 软删除
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
const EXECUTE_IMMEDIATELY = 1; // 立即执行
|
||||||
|
const EXECUTE_ONCE = 2; // 执行一次
|
||||||
|
const EXECUTE_FORBIDDEN = 3; // 停止执行
|
||||||
|
|
||||||
|
}
|
53
catch/monitor/model/CrontabLog.php
Normal file
53
catch/monitor/model/CrontabLog.php
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace catchAdmin\monitor\model;
|
||||||
|
|
||||||
|
use catchAdmin\monitor\model\search\CrontabLogSearch;
|
||||||
|
use catcher\base\CatchModel;
|
||||||
|
|
||||||
|
class CrontabLog extends CatchModel
|
||||||
|
{
|
||||||
|
use CrontabLogSearch;
|
||||||
|
|
||||||
|
protected $name = 'crontab_log';
|
||||||
|
|
||||||
|
protected $field = [
|
||||||
|
'id', //
|
||||||
|
'crontab_id', // crontab 任务ID
|
||||||
|
'used_time', // 任务消耗时间
|
||||||
|
'status', // 1 成功 2 失败
|
||||||
|
'error_message', // 错误信息
|
||||||
|
'created_at', // 创建时间
|
||||||
|
'updated_at', // 更新时间
|
||||||
|
'deleted_at', // 软删除
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
const SUCCESS = 1;
|
||||||
|
const FAILED = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取日志列表
|
||||||
|
*
|
||||||
|
* @time 2020年09月15日
|
||||||
|
* @throws \think\db\exception\DbException
|
||||||
|
* @return mixed|\think\Paginator
|
||||||
|
*/
|
||||||
|
public function getList()
|
||||||
|
{
|
||||||
|
return $this->catchLeftJoin(Crontab::class, 'id', 'crontab_id', ['name', 'group', 'task'])
|
||||||
|
->catchSearch()
|
||||||
|
->catchOrder()
|
||||||
|
->field(['used_time', 'error_message', 'crontab_log.status', 'crontab_log.id', 'crontab_log.created_at'])
|
||||||
|
->paginate();
|
||||||
|
}
|
||||||
|
}
|
39
catch/monitor/model/search/CrontabLogSearch.php
Normal file
39
catch/monitor/model/search/CrontabLogSearch.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
namespace catchAdmin\monitor\model\search;
|
||||||
|
|
||||||
|
trait CrontabLogSearch
|
||||||
|
{
|
||||||
|
public function searchCrontabIdAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
return $query->where('crontab_id', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function searchNameAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
return $query->whereLike('crontab.name', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function searchStatusAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
return $query->where('status', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function searchStartAtAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
return $query->where($this->aliasField('created_at'), '>=', strtotime($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function searchEndAtAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
return $query->where($this->aliasField('created_at'), '<=', strtotime($value));
|
||||||
|
}
|
||||||
|
}
|
24
catch/monitor/model/search/CrontabSearch.php
Normal file
24
catch/monitor/model/search/CrontabSearch.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
namespace catchAdmin\monitor\model\search;
|
||||||
|
|
||||||
|
trait CrontabSearch
|
||||||
|
{
|
||||||
|
public function searchNameAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
return $query->whereLike('name', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function searchStatusAttr($query, $value, $data)
|
||||||
|
{
|
||||||
|
return $query->whereLike('status', $value);
|
||||||
|
}
|
||||||
|
}
|
15
catch/monitor/module.json
Normal file
15
catch/monitor/module.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "系统监控",
|
||||||
|
"alias": "monitor",
|
||||||
|
"description": "系统监控模块",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"keywords": [],
|
||||||
|
"order": 0,
|
||||||
|
"services": [
|
||||||
|
"\\catchAdmin\\monitor\\MonitorService"
|
||||||
|
],
|
||||||
|
"aliases": [],
|
||||||
|
"files": [],
|
||||||
|
"requires": [],
|
||||||
|
"enable": false
|
||||||
|
}
|
22
catch/monitor/route.php
Normal file
22
catch/monitor/route.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~{$year} http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
// you should use `$router`
|
||||||
|
$router->group('monitor', function () use ($router){
|
||||||
|
// crontab路由
|
||||||
|
$router->resource('crontab', '\catchAdmin\monitor\controller\Crontab');
|
||||||
|
$router->put('crontab/enable/<id>', '\catchAdmin\monitor\controller\Crontab@disOrEnable');
|
||||||
|
|
||||||
|
// crontab 日志
|
||||||
|
$router->get('crontab/log', '\catchAdmin\monitor\controller\CrontabLog@index');
|
||||||
|
$router->delete('crontab/log/<id>', '\catchAdmin\monitor\controller\CrontabLog@delete');
|
||||||
|
|
||||||
|
})->middleware('auth');
|
10
extend/catcher/base/CatchCronTask.php
Normal file
10
extend/catcher/base/CatchCronTask.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | CatchAdmin [Just Like ~ ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2017~2020 http://catchadmin.com All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( https://github.com/yanwenwu/catch-admin/blob/master/LICENSE.txt )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: JaguarJack [ njphper@gmail.com ]
|
||||||
|
// +----------------------------------------------------------------------
|
@ -1,104 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare (strict_types = 1);
|
|
||||||
|
|
||||||
namespace catcher\command;
|
|
||||||
|
|
||||||
use catcher\library\crontab\Master;
|
|
||||||
use think\console\Command;
|
|
||||||
use think\console\Input;
|
|
||||||
use think\console\input\Argument;
|
|
||||||
use think\console\input\Option;
|
|
||||||
use think\console\Output;
|
|
||||||
|
|
||||||
class CatchScheduleCommand extends Command
|
|
||||||
{
|
|
||||||
protected function configure()
|
|
||||||
{
|
|
||||||
// 指令配置
|
|
||||||
$this->setName('catch:schedule')
|
|
||||||
->addArgument('option', Argument::OPTIONAL, '[start|reload|stop|restart||status]', 'start')
|
|
||||||
->addOption('daemon', '-d', Option::VALUE_NONE, 'daemon mode')
|
|
||||||
->setDescription('start task schedule');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function execute(Input $input, Output $output)
|
|
||||||
{
|
|
||||||
if (!extension_loaded('swoole')) {
|
|
||||||
$output->error('Swoole Extension Not Installed! You can use [pecl] to install swoole');
|
|
||||||
} else {
|
|
||||||
$master = new Master();
|
|
||||||
if ($this->input->hasOption('daemon')) {
|
|
||||||
$master->daemon();
|
|
||||||
}
|
|
||||||
$this->{$input->getArgument('option')}($master);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 进程启动
|
|
||||||
*
|
|
||||||
* @time 2020年07月07日
|
|
||||||
* @param Master $process
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function start(Master $process)
|
|
||||||
{
|
|
||||||
$process->start();
|
|
||||||
$this->output->info($process->renderProcessesStatusToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 状态输出
|
|
||||||
*
|
|
||||||
* @time 2020年07月07日
|
|
||||||
* @param Master $process
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function status(Master $process)
|
|
||||||
{
|
|
||||||
$process->status();
|
|
||||||
|
|
||||||
$this->output->info($process->output());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止任务
|
|
||||||
*
|
|
||||||
* @time 2020年07月07日
|
|
||||||
* @param Master $process
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function stop(Master $process)
|
|
||||||
{
|
|
||||||
$process->stop();
|
|
||||||
|
|
||||||
$this->output->info('stop catch schedule successfully');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重启任务
|
|
||||||
*
|
|
||||||
* @time 2020年07月07日
|
|
||||||
* @param Master $process
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function reload(Master $process)
|
|
||||||
{
|
|
||||||
$process->reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重启
|
|
||||||
*
|
|
||||||
* @time 2020年07月07日
|
|
||||||
* @param Master $process
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function restart(Master $process)
|
|
||||||
{
|
|
||||||
$process->stop();
|
|
||||||
|
|
||||||
$process->start();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user