ea
This commit is contained in:
+132
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/**
|
||||
* kiri-crontab 独立运行入口脚本
|
||||
*
|
||||
* 使用方式:
|
||||
* php bin/crontab start 启动调度器
|
||||
* php bin/crontab stop 停止调度器
|
||||
* php bin/crontab restart 重启调度器
|
||||
* php bin/crontab status 查看状态
|
||||
*
|
||||
* 任务定义方式:
|
||||
* 1. 配置文件: config/crontab.php 的 tasks 中声明
|
||||
* 2. 注解自动扫描: 在任务类上使用 #[Crontab] 注解,配置 scan_paths 目录
|
||||
*
|
||||
* 确保项目根目录有 config/crontab.php 配置文件
|
||||
* 并在其中定义 Redis 连接 (redis)、调度参数 (scheduler) 和扫描路径 (scan_paths)
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
// 自动加载
|
||||
$autoloadFiles = [
|
||||
__DIR__ . '/../vendor/autoload.php',
|
||||
__DIR__ . '/../../../vendor/autoload.php',
|
||||
__DIR__ . '/../../autoload.php',
|
||||
];
|
||||
|
||||
$autoloadPath = null;
|
||||
foreach ($autoloadFiles as $file) {
|
||||
if (file_exists($file)) {
|
||||
$autoloadPath = $file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($autoloadPath === null) {
|
||||
fwrite(STDERR, "未找到 autoload.php,请先执行 composer install" . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require $autoloadPath;
|
||||
|
||||
use Kiri\Crontab\CrontabCommand;
|
||||
use Kiri\Crontab\TaskRegistry;
|
||||
|
||||
// 解析命令行参数
|
||||
$args = $argv;
|
||||
$script = array_shift($args);
|
||||
$action = array_shift($args) ?: 'status';
|
||||
|
||||
// 查找配置文件
|
||||
$configFiles = [
|
||||
getcwd() . '/config/crontab.php',
|
||||
__DIR__ . '/../config/crontab.php',
|
||||
];
|
||||
$configPath = null;
|
||||
foreach ($configFiles as $file) {
|
||||
if (file_exists($file)) {
|
||||
$configPath = $file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($configPath === null) {
|
||||
fwrite(STDERR, "未找到配置文件 config/crontab.php" . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$config = require $configPath;
|
||||
|
||||
if (!is_array($config)) {
|
||||
fwrite(STDERR, "配置文件格式错误" . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// 初始化任务注册中心 (静态注册表)
|
||||
// 1. 注册配置文件中的任务
|
||||
$taskList = $config['tasks'] ?? [];
|
||||
foreach ($taskList as $taskConfig) {
|
||||
try {
|
||||
TaskRegistry::register($taskConfig);
|
||||
} catch (\Throwable $throwable) {
|
||||
fwrite(STDERR, "任务注册失败: {$throwable->getMessage()}" . PHP_EOL);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 发现注解任务 (检查类上的 #[Crontab] 注解)
|
||||
foreach (get_declared_classes() as $className) {
|
||||
try {
|
||||
$reflect = new ReflectionClass($className);
|
||||
if ($reflect->isAbstract()) continue;
|
||||
if (!in_array(Kiri\Crontab\TaskInterface::class, class_implements($className), true)) continue;
|
||||
|
||||
$attributes = $reflect->getAttributes(Kiri\Crontab\Annotate\Crontab::class);
|
||||
if (empty($attributes)) continue;
|
||||
|
||||
$instance = $attributes[0]->newInstance();
|
||||
$expr = $instance->buildExpression();
|
||||
if ($expr === '') continue;
|
||||
|
||||
Kiri\Crontab\TaskRegistry::register([
|
||||
'class' => $className,
|
||||
'name' => $instance->name !== '' ? $instance->name : $className,
|
||||
'expression' => $expr,
|
||||
'status' => $instance->status,
|
||||
]);
|
||||
} catch (\Throwable) {}
|
||||
}
|
||||
|
||||
echo "[Crontab] 任务总数: " . TaskRegistry::count() . PHP_EOL;
|
||||
|
||||
// PID 文件和日志文件
|
||||
$pidFile = $config['scheduler']['pid_file'] ?? (getcwd() . '/storage/crontab.pid');
|
||||
$logFile = $config['scheduler']['log_file'] ?? '';
|
||||
|
||||
// 创建命令实例
|
||||
$command = new CrontabCommand($pidFile, $logFile);
|
||||
|
||||
// 路由到对应操作
|
||||
try {
|
||||
match ($action) {
|
||||
'start' => $command->start($config),
|
||||
'stop' => $command->stop(),
|
||||
'restart' => $command->restart($config),
|
||||
'status' => $command->status(),
|
||||
default => fwrite(STDERR, "未知操作: {$action} (支持: start|stop|restart|status)" . PHP_EOL),
|
||||
};
|
||||
} catch (\Throwable $throwable) {
|
||||
fwrite(STDERR, "执行失败: {$throwable->getMessage()}" . PHP_EOL);
|
||||
fwrite(STDERR, "{$throwable->getTraceAsString()}" . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user