2026-06-28 17:06:12 +08:00
|
|
|
# kiri-crontab
|
|
|
|
|
|
|
|
|
|
基于 Redis + Swoole 的 PHP 定时任务调度系统。
|
|
|
|
|
|
|
|
|
|
## 功能特性
|
|
|
|
|
|
|
|
|
|
- **闹钟模式**: 像设置闹钟一样声明任务 `hour: 3, minute: 0, loop: true`
|
|
|
|
|
- **间隔执行**: `tick: 30` 每30秒、`tickMinute: 5` 每5分钟、`tickHour: 1` 每1小时
|
|
|
|
|
- **一次性任务**: `year: 2026, month: 12, day: 22, hour: 11` 指定时刻执行一次
|
|
|
|
|
- **Cron 兜底**: 复杂场景用 `cron: '*/5 * * * *'`
|
|
|
|
|
- **动态投递**: 运行时通过 `submitToCrontab()` 随时提交、`cancelCrontabTask()` 取消
|
|
|
|
|
- **类注解**: `#[Crontab]` 在类上声明调度参数,CrontabProcess 启动时自动发现
|
|
|
|
|
- **协程并发**: 到期任务通过 Swoole 协程并发执行
|
|
|
|
|
- **分布式锁**: Redis 主锁 + 任务锁防止重复执行
|
|
|
|
|
|
|
|
|
|
## 快速开始
|
|
|
|
|
|
|
|
|
|
### 安装
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
composer require game-worker/kiri-crontab
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 注解模式
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
<?php
|
|
|
|
|
namespace App\Task;
|
|
|
|
|
|
|
|
|
|
use Kiri\Crontab\Annotate\Crontab;
|
|
|
|
|
use Kiri\Crontab\TaskInterface;
|
|
|
|
|
|
|
|
|
|
#[Crontab(name: '清理日志', hour: 3, minute: 0, loop: true)]
|
|
|
|
|
class CleanLogTask implements TaskInterface
|
|
|
|
|
{
|
|
|
|
|
public function handle(): void
|
|
|
|
|
{
|
|
|
|
|
echo "清理日志..." . PHP_EOL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[Crontab(name: '心跳', tick: 30, loop: true)]
|
|
|
|
|
class HeartbeatTask implements TaskInterface
|
|
|
|
|
{
|
|
|
|
|
public function handle(): void
|
|
|
|
|
{
|
|
|
|
|
echo "心跳检测..." . PHP_EOL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 动态投递
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
use function Kiri\Crontab\submitToCrontab;
|
|
|
|
|
use function Kiri\Crontab\cancelCrontabTask;
|
|
|
|
|
|
|
|
|
|
// 每秒检查匹配结果,匹配成功后在 handle() 中自停
|
|
|
|
|
class MatchCheckTask implements TaskInterface
|
|
|
|
|
{
|
|
|
|
|
public function handle(): void
|
|
|
|
|
{
|
|
|
|
|
if ($this->isMatched()) {
|
|
|
|
|
// 执行完后自动移除,不再调度
|
|
|
|
|
CrontabScheduler::getInstance()?->cancelCurrentTask();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// 未匹配,继续检查
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 业务代码中动态投递
|
|
|
|
|
$taskKey = submitToCrontab(MatchCheckTask::class, 'every:1', '匹配检查 #123');
|
|
|
|
|
|
|
|
|
|
// 条件满足时也可以外部取消
|
|
|
|
|
cancelCrontabTask($taskKey);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 配置文件
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
// config/crontab.php
|
|
|
|
|
return [
|
|
|
|
|
'redis' => ['host' => '127.0.0.1', 'port' => 6379],
|
|
|
|
|
'scheduler' => ['tick_interval' => 1],
|
|
|
|
|
'tasks' => [
|
|
|
|
|
['class' => App\Task\CleanLogTask::class, 'name' => '清理日志', 'expression' => 'daily:03:00'],
|
|
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 启动
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
php bin/crontab start / stop / restart / status
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 集成到 kiri-core
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
// config/servers.php
|
|
|
|
|
'process' => [\Kiri\Crontab\CrontabProcess::class],
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 调度参数一览
|
|
|
|
|
|
|
|
|
|
| 参数 | 示例 | 含义 |
|
|
|
|
|
|------|------|------|
|
|
|
|
|
| `tick` | `tick: 30` | 每 30 秒循环 |
|
|
|
|
|
| `tickMinute` | `tickMinute: 5` | 每 5 分钟循环 |
|
|
|
|
|
| `tickHour` | `tickHour: 1` | 每 1 小时循环 |
|
|
|
|
|
| `hour` `minute` `second` | `hour: 3, minute: 0, loop: true` | 每天 03:00 |
|
|
|
|
|
| `minute` | `minute: 30, loop: true` | 每小时 :30 |
|
|
|
|
|
| `year` `month` `day` ... | `year: 2026, month: 12, day: 22` | 指定时刻一次性 |
|
|
|
|
|
| `cron` | `cron: '*\/5 * * * *'` | cron 表达式 |
|
|
|
|
|
|
|
|
|
|
## 架构
|
|
|
|
|
|
|
|
|
|
详见 [DESIGN.md](./DESIGN.md)
|