eee
This commit is contained in:
@@ -8,7 +8,9 @@
|
||||
- cron 表达式:标准 5 字段 cron 表达式调度
|
||||
- 一次性任务:执行后自动移除
|
||||
- 任务暂停/恢复:通过 Redis 标记控制任务启停
|
||||
- **注解驱动**: 使用 `#[Crontab]` 注解声明任务,支持自动扫描发现
|
||||
- **注解驱动**: 使用 `#[Crontab]` 注解声明任务,启动时自动扫描发现
|
||||
- **事件驱动**: 通过 kiri-core PSR-14 事件系统分发任务生命周期事件
|
||||
- **幽灵任务清理**: 启动时自动清理 Redis 中已从配置移除的任务
|
||||
|
||||
## 二、核心组件
|
||||
|
||||
@@ -18,10 +20,16 @@
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────────┐ │
|
||||
│ │CrontabCommand │───▶│ CrontabScheduler │ │
|
||||
│ │ (控制台命令) │ │ (调度引擎) │ │
|
||||
│ │CrontabCommand │───▶│ CrontabProcess │ │
|
||||
│ │ (Symfony命令) │ │ (继承AbstractProcess) │
|
||||
│ └──────────────┘ └────────┬─────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────────┐ │
|
||||
│ │ CrontabScheduler │ │
|
||||
│ │ (继承Component) │ │
|
||||
│ └────────┬─────────┘ │
|
||||
│ │ │
|
||||
│ ┌─────────▼─────────┐ │
|
||||
│ │ TaskRegistry │ │
|
||||
│ │ (任务注册中心) │ │
|
||||
@@ -41,6 +49,11 @@
|
||||
│ │ └──────────────┘ │ │
|
||||
│ └────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────┐ │
|
||||
│ │ kiri-core 事件系统 (PSR-14) │ │
|
||||
│ │ OnTaskBeforeExecute → OnTaskExecuted → OnTaskFailed│ │
|
||||
│ └────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
@@ -65,7 +78,7 @@ Type: Hash
|
||||
Fields:
|
||||
class - 任务处理类完整路径 (如 App\Task\CleanLogTask)
|
||||
name - 任务显示名称
|
||||
expression - 调度表达式 (every:60 | cron:*\/5 * * * * | daily:03:00 | at:1234567890)
|
||||
expression - 调度表达式 (every:60 | cron:*/5 * * * * | daily:03:00 | at:1234567890)
|
||||
next_run - 下次执行时间戳 (秒)
|
||||
last_run - 上次执行时间戳 (秒)
|
||||
status - 状态: active / paused / disabled
|
||||
@@ -78,7 +91,7 @@ Fields:
|
||||
```
|
||||
Key: crontab:lock:task:{taskKey}
|
||||
Type: String
|
||||
Value: Swoole Worker ID + Timestamp
|
||||
Value: Timestamp
|
||||
TTL: 任务超时时间 (默认 300s)
|
||||
```
|
||||
|
||||
@@ -90,7 +103,7 @@ TTL: 任务超时时间 (默认 300s)
|
||||
Key: crontab:lock:master
|
||||
Type: String
|
||||
Value: Worker PID
|
||||
TTL: 60s (定期续期)
|
||||
TTL: 60s (并发执行期间由独立协程定期续期)
|
||||
```
|
||||
|
||||
防止多实例同时调度,用 SET NX EX + Lua 脚本实现。
|
||||
@@ -105,6 +118,17 @@ Member: 当前正在执行的任务 key 列表
|
||||
|
||||
用于监控哪些任务正在运行中。
|
||||
|
||||
### 3.6 任务移除标记
|
||||
|
||||
```
|
||||
Key: crontab:removal:{taskKey}
|
||||
Type: String
|
||||
Value: "1"
|
||||
TTL: 60s
|
||||
```
|
||||
|
||||
当任务内部调用 cancelCurrentTask() 时设置此标记,执行完成后检查并清理。
|
||||
|
||||
## 四、调度表达式
|
||||
|
||||
| 格式 | 示例 | 含义 |
|
||||
@@ -115,7 +139,7 @@ Member: 当前正在执行的任务 key 列表
|
||||
| `every:{时}h` | `every:1h` | 每 1 小时执行 |
|
||||
| `daily:{HH:MM}` | `daily:03:00` | 每天凌晨 3 点 |
|
||||
| `hourly:{MM}` | `hourly:30` | 每小时第 30 分 |
|
||||
| `cron:{表达式}` | `cron:*\/5 * * * *` | 标准 5 字段 cron |
|
||||
| `cron:{表达式}` | `cron:*/5 * * * *` | 标准 5 字段 cron |
|
||||
| `at:{时间戳}` | `at:1719590400` | 指定时间戳一次性 |
|
||||
|
||||
## 五、调度流程
|
||||
@@ -129,6 +153,7 @@ Member: 当前正在执行的任务 key 列表
|
||||
┌──────────────────────────────────────┐
|
||||
│ 1. 扫描 TaskRegistry 注册的所有任务 │
|
||||
│ 将未注册到 Redis 的任务写入 Hash │
|
||||
│ 清理 Redis 中已移除的幽灵任务 │
|
||||
│ 将任务加入 ZSET 调度队列 │
|
||||
└────────────────┬─────────────────────┘
|
||||
│
|
||||
@@ -151,18 +176,22 @@ Member: 当前正在执行的任务 key 列表
|
||||
└──────────┬───────────┘ │
|
||||
│ 有任务 │
|
||||
▼ │
|
||||
┌──────────────────────────────────────┐ │
|
||||
│ 4. 遍历到期任务 (协程并发) │ │
|
||||
│ - 启动主锁续期协程 │ │
|
||||
│ - 通过 Channel 控制最大并发数 │ │
|
||||
│ - 获取任务锁 │ │
|
||||
│ - 分发 OnTaskBeforeExecute 事件 │ │
|
||||
│ - 执行任务 handle() │ │
|
||||
│ - 分发 OnTaskExecuted/OnTaskFailed │ │
|
||||
│ - 计算下次执行时间 │ │
|
||||
│ - 更新 ZSET 分数 │ │
|
||||
│ - 停止锁续期协程 │ │
|
||||
└──────────────────────────────────────┘ │
|
||||
│ │
|
||||
▼ │
|
||||
┌──────────────────────┐ │
|
||||
│ 4. 遍历到期任务 │ │
|
||||
│ - 获取任务锁 │ │
|
||||
│ - 执行任务 handle() │ │
|
||||
│ - 记录日志/更新状态 │◀─────────────────────┘
|
||||
│ - 计算下次执行时间 │
|
||||
│ - 更新 ZSET 分数 │
|
||||
└──────────┬───────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────┐
|
||||
│ 5. sleep(1) 等待下个 │
|
||||
│ 5. sleep(1) 等待下个 │◀─────────────────────┘
|
||||
│ tick │
|
||||
└──────────────────────┘
|
||||
```
|
||||
@@ -183,11 +212,31 @@ Member: 当前正在执行的任务 key 列表
|
||||
active ──▶ paused ──▶ active (暂停/恢复)
|
||||
active ──▶ disabled (禁用,从 ZSET 移除)
|
||||
一次性任务执行完成后: 从 ZSET 和 Redis 中移除
|
||||
任务从配置中移除: 启动时自动清理 (幽灵任务清理)
|
||||
```
|
||||
|
||||
## 七、与 kiri-core 集成方式
|
||||
## 七、事件系统
|
||||
|
||||
### 7.1 作为 Composer 包引入
|
||||
调度器通过 kiri-core PSR-14 事件系统在任务执行的各个阶段分发事件:
|
||||
|
||||
| 事件 | 触发时机 | 参数 |
|
||||
|------|---------|------|
|
||||
| `OnTaskBeforeExecute` | 任务执行前 | taskKey, className, taskName |
|
||||
| `OnTaskExecuted` | 任务执行成功 | taskKey, className, taskName, duration, nextRun |
|
||||
| `OnTaskFailed` | 任务执行失败 | taskKey, className, taskName, error, duration, nextRun |
|
||||
|
||||
监听器注册方式(config/events.php):
|
||||
```php
|
||||
return [
|
||||
\Kiri\Crontab\Events\OnTaskFailed::class => [
|
||||
[App\Listener\CrontabAlertListener::class, 'process'],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
## 八、与 kiri-core 集成方式
|
||||
|
||||
### 8.1 作为 Composer 包引入
|
||||
```json
|
||||
{
|
||||
"require": {
|
||||
@@ -196,22 +245,32 @@ Member: 当前正在执行的任务 key 列表
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 通过 Provider 注册到框架
|
||||
### 8.2 通过 Provider 注册命令
|
||||
CrontabProviders 自动将 `sw:crontab` 命令注册到 Console Application。
|
||||
|
||||
### 8.3 通过 Process 集成
|
||||
```php
|
||||
// config/servers.php 中添加
|
||||
'process' => [
|
||||
\Kiri\Crontab\CrontabProcess::class,
|
||||
],
|
||||
```
|
||||
CrontabProcess 继承 AbstractProcess,支持框架的生命周期管理(信号处理、优雅退出)。
|
||||
|
||||
### 7.3 独立运行模式
|
||||
### 8.4 独立运行模式
|
||||
```bash
|
||||
php bin/crontab start
|
||||
php bin/crontab stop
|
||||
php bin/crontab restart
|
||||
php bin/crontab status
|
||||
```
|
||||
|
||||
### 7.4 注解驱动注册方式
|
||||
### 8.5 kiri-core 控制台模式
|
||||
```bash
|
||||
php kiri.php sw:crontab start|stop|restart|status
|
||||
```
|
||||
|
||||
### 8.6 注解驱动注册方式
|
||||
```php
|
||||
use Kiri\Crontab\Annotate\Crontab;
|
||||
use Kiri\Crontab\TaskInterface;
|
||||
@@ -226,70 +285,75 @@ class CleanLogTask implements TaskInterface
|
||||
}
|
||||
```
|
||||
|
||||
在配置中指定扫描路径:
|
||||
```php
|
||||
// config/crontab.php
|
||||
'scan_paths' => [
|
||||
'app/Task',
|
||||
'app/Crontab',
|
||||
],
|
||||
```
|
||||
任务类实现 TaskInterface 并使用 `#[Crontab]` 注解后,CrontabProcess 启动时自动通过 `get_declared_classes()` 发现并注册。
|
||||
|
||||
## 八、注解扫描流程
|
||||
## 九、注解扫描流程
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────┐
|
||||
│ CrontabScanner::scan($directory) │
|
||||
│ CrontabProcess::discoverAnnotationTasks() │
|
||||
└────────────────┬─────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────┐
|
||||
│ 1. 递归遍历目录下所有 PHP 文件 │
|
||||
│ 跳过 vendor/tests/cache/storage │
|
||||
│ 1. 遍历 get_declared_classes() │
|
||||
│ 遍历所有已加载的 PHP 类 │
|
||||
└────────────────┬─────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────┐
|
||||
│ 2. require_once 加载文件 │
|
||||
│ get_declared_classes() 获取新类 │
|
||||
└────────────────┬─────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────┐
|
||||
│ 3. 检查类是否 implements TaskInterface│
|
||||
│ 2. 检查类是否 implements TaskInterface│
|
||||
│ ──否──▶ 跳过 │
|
||||
└────────────────┬─────────────────────┘
|
||||
│ 是
|
||||
▼
|
||||
┌──────────────────────────────────────┐
|
||||
│ 4. ReflectionClass::getAttributes( │
|
||||
│ 3. ReflectionClass::getAttributes( │
|
||||
│ Crontab::class) 读取注解 │
|
||||
│ ──无──▶ 跳过 │
|
||||
└────────────────┬─────────────────────┘
|
||||
│ 有
|
||||
▼
|
||||
┌──────────────────────────────────────┐
|
||||
│ 5. $registry->register([ │
|
||||
│ 'class' => $className, │
|
||||
│ 'name' => $crontab->name, │
|
||||
│ 'expression' => $crontab->expr, │
|
||||
│ 'status' => $crontab->status, │
|
||||
│ 4. 调用 buildExpression() 生成表达式 │
|
||||
│ 验证表达式非空 │
|
||||
│ ──空──▶ 跳过 │
|
||||
└────────────────┬─────────────────────┘
|
||||
│ 有效
|
||||
▼
|
||||
┌──────────────────────────────────────┐
|
||||
│ 5. TaskRegistry::register([ │
|
||||
│ 'class' => $className, │
|
||||
│ 'name' => $crontab->name, │
|
||||
│ 'expression' => $expr, │
|
||||
│ 'status' => $crontab->status│
|
||||
│ ]); │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 九、依赖关系
|
||||
## 十、依赖关系
|
||||
|
||||
```
|
||||
kiri-crontab
|
||||
├── PHP >= 8.5
|
||||
├── ext-swoole (协程/进程)
|
||||
├── ext-redis (Redis 客户端)
|
||||
├── psr/log (PSR-3 日志)
|
||||
└── symfony/console (可选,如集成 kiri-core 则复用项目已有的)
|
||||
├── ext-swoole (协程/进程)
|
||||
├── ext-redis (Redis 客户端)
|
||||
├── psr/log (PSR-3 日志)
|
||||
├── psr/event-dispatcher (PSR-14 事件)
|
||||
└── symfony/console (命令行集成)
|
||||
```
|
||||
|
||||
## 十、目录结构
|
||||
与 kiri-core 框架的关系:
|
||||
```
|
||||
kiri-crontab (外挂包)
|
||||
├── 继承 Kiri\Abstracts\Component (CrontabScheduler)
|
||||
├── 继承 Kiri\Abstracts\Providers (CrontabProviders)
|
||||
├── 继承 Kiri\Server\Processes\AbstractProcess (CrontabProcess)
|
||||
├── 使用 Kiri\Events\EventDispatch (事件分发)
|
||||
└── 集成 Symfony\Component\Console\Command\Command
|
||||
```
|
||||
|
||||
## 十一、目录结构
|
||||
|
||||
```
|
||||
kiri-crontab/
|
||||
@@ -304,12 +368,12 @@ kiri-crontab/
|
||||
│ ├── TaskInterface.php # 任务接口
|
||||
│ ├── TaskConfig.php # 任务配置值对象
|
||||
│ ├── TaskRegistry.php # 任务注册中心
|
||||
│ ├── CrontabScheduler.php # 核心调度引擎
|
||||
│ ├── CrontabProcess.php # Swoole 进程适配器
|
||||
│ ├── CrontabCommand.php # 控制台命令
|
||||
│ ├── CrontabScanner.php # 注解任务扫描器
|
||||
│ ├── CrontabScheduler.php # 核心调度引擎 (继承 Component)
|
||||
│ ├── CrontabProcess.php # Swoole 进程适配器 (继承 AbstractProcess)
|
||||
│ ├── CrontabCommand.php # Symfony 控制台命令
|
||||
│ ├── CrontabProviders.php # kiri-core Provider 集成
|
||||
│ ├── CronExpression.php # Cron 表达式解析器
|
||||
│ ├── functions.php # 全局辅助函数
|
||||
│ ├── Annotate/
|
||||
│ │ └── Crontab.php # #[Crontab] 注解类
|
||||
│ └── Events/
|
||||
|
||||
Reference in New Issue
Block a user