签入版本
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
:::tip 定时任务
|
||||
定时任务模块基于 APScheduler 实现,支持 Cron 表达式调度、任务执行日志、动态启停等功能。包含 job(任务定义)、job_log(执行日志)两个子模块。
|
||||
:::
|
||||
|
||||
## 模块结构
|
||||
|
||||
```
|
||||
application/job/
|
||||
├── models.py # 任务模型
|
||||
├── forms.py # 表单验证
|
||||
├── services.py # 业务逻辑层
|
||||
├── views.py # 视图层
|
||||
└── urls.py # 路由配置
|
||||
|
||||
application/job_log/
|
||||
├── models.py # 执行日志模型
|
||||
├── services.py # 日志业务逻辑
|
||||
└── urls.py # 路由配置
|
||||
```
|
||||
|
||||
## 任务模型
|
||||
|
||||
```python
|
||||
# application/job/models.py
|
||||
from application.models import BaseModel
|
||||
|
||||
class Job(BaseModel):
|
||||
"""定时任务模型类"""
|
||||
class Meta:
|
||||
db_table = 'django_job'
|
||||
|
||||
job_name = models.CharField(max_length=255, verbose_name='任务名称')
|
||||
job_alias = models.CharField(max_length=255, null=True, blank=True, verbose_name='任务别名')
|
||||
job_group = models.CharField(max_length=255, null=True, blank=True, verbose_name='任务分组')
|
||||
job_trigger = models.CharField(max_length=255, null=True, blank=True, verbose_name='任务触发器')
|
||||
status = models.IntegerField(default=0, verbose_name='任务状态:0-未发布 1-运行中 2-暂停 3-删除')
|
||||
cron_expression = models.CharField(max_length=255, null=True, blank=True, verbose_name='Cron表达式')
|
||||
execute_policy = models.IntegerField(default=1, verbose_name='执行策略:1-立即执行 2-执行一次 3-放弃执行')
|
||||
is_sync = models.IntegerField(default=0, verbose_name='是否同步任务:0-否 1-是')
|
||||
url = models.CharField(max_length=255, null=True, blank=True, verbose_name='任务URL')
|
||||
params = models.TextField(null=True, blank=True, verbose_name='任务参数')
|
||||
note = models.CharField(max_length=255, null=True, blank=True, verbose_name='任务备注')
|
||||
```
|
||||
|
||||
### 字段说明
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `job_name` | str | 任务名称(唯一标识) |
|
||||
| `job_alias` | str | 任务别名(显示用) |
|
||||
| `job_group` | str | 任务分组(如"系统任务"、"业务任务") |
|
||||
| `job_trigger` | str | 触发器类型(cron/interval/date) |
|
||||
| `status` | int | 状态:0-未发布 1-运行中 2-暂停 3-删除 |
|
||||
| `cron_expression` | str | Cron 表达式 |
|
||||
| `execute_policy` | int | 执行策略:1-立即执行 2-执行一次 3-放弃执行 |
|
||||
| `is_sync` | int | 是否同步:0-异步 1-同步 |
|
||||
| `url` | str | 任务执行的 URL |
|
||||
| `params` | str | 任务参数(JSON 格式) |
|
||||
|
||||
## 执行日志模型
|
||||
|
||||
```python
|
||||
# application/job_log/models.py
|
||||
from application.models import BaseModel
|
||||
|
||||
class JobLog(BaseModel):
|
||||
"""定时任务日志模型类"""
|
||||
class Meta:
|
||||
db_table = 'django_job_log'
|
||||
|
||||
job_id = models.IntegerField(default=0, verbose_name='任务ID')
|
||||
job_name = models.CharField(max_length=255, verbose_name='任务名称')
|
||||
job_group = models.CharField(max_length=255, null=True, blank=True, verbose_name='任务分组')
|
||||
job_trigger = models.CharField(max_length=255, null=True, blank=True, verbose_name='任务触发器')
|
||||
job_message = models.CharField(max_length=500, null=True, blank=True, verbose_name='任务日志信息')
|
||||
cron_expression = models.CharField(max_length=255, null=True, blank=True, verbose_name='Cron表达式')
|
||||
status = models.IntegerField(default=0, verbose_name='执行状态:0-正常 1-失败')
|
||||
start_time = models.DateTimeField(null=True, blank=True, verbose_name='执行开始时间')
|
||||
end_time = models.DateTimeField(null=True, blank=True, verbose_name='执行结束时间')
|
||||
consume_time = models.BigIntegerField(default=0, verbose_name='执行耗时(毫秒)')
|
||||
exception_info = models.TextField(null=True, blank=True, verbose_name='异常信息')
|
||||
```
|
||||
|
||||
## Cron 表达式
|
||||
|
||||
| 字段 | 允许值 | 允许的特殊字符 |
|
||||
|------|--------|---------------|
|
||||
| 秒 | 0-59 | , - * / |
|
||||
| 分 | 0-59 | , - * / |
|
||||
| 时 | 0-23 | , - * / |
|
||||
| 日 | 1-31 | , - * / |
|
||||
| 月 | 1-12 | , - * / |
|
||||
| 周 | 0-7 | , - * / |
|
||||
|
||||
### 常用示例
|
||||
|
||||
```
|
||||
0 0/5 * * * ? 每5分钟执行
|
||||
0 0 2 * * ? 每天凌晨2点执行
|
||||
0 0 0 1 * ? 每月1号零点执行
|
||||
0 0 * * * ? 每小时执行
|
||||
0 0 9 * * 1-5 工作日上午9点执行
|
||||
0 0/30 8-18 * * ? 工作时间每30分钟执行
|
||||
```
|
||||
|
||||
### 特殊字符说明
|
||||
|
||||
| 字符 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| `*` | 所有值 | `* * * * *` 每分钟 |
|
||||
| `?` | 不指定值(日和周) | `0 0 12 * * ?` |
|
||||
| `-` | 范围 | `1-5` 表示 1 到 5 |
|
||||
| `,` | 列表 | `1,3,5` 表示 1、3、5 |
|
||||
| `/` | 步长 | `0/5` 从 0 开始每 5 |
|
||||
|
||||
## 任务状态
|
||||
|
||||
```
|
||||
未发布(0) → 运行中(1) → 暂停(2) → 运行中(1) → 删除(3)
|
||||
↓
|
||||
删除(3)
|
||||
```
|
||||
|
||||
| 状态 | 说明 | 可执行操作 |
|
||||
|------|------|-----------|
|
||||
| 0-未发布 | 任务已创建但未启动 | 启动、编辑、删除 |
|
||||
| 1-运行中 | 任务正在调度执行 | 暂停、立即执行、编辑 |
|
||||
| 2-暂停 | 任务已暂停 | 恢复、编辑、删除 |
|
||||
| 3-删除 | 任务已删除(逻辑删除) | 无 |
|
||||
|
||||
## 执行策略
|
||||
|
||||
| 策略 | 说明 | 场景 |
|
||||
|------|------|------|
|
||||
| 1-立即执行 | 错过执行时间后立即补执行 | 关键任务(如数据备份) |
|
||||
| 2-执行一次 | 错过执行时间后只执行一次 | 普通任务 |
|
||||
| 3-放弃执行 | 错过执行时间后放弃本次执行 | 非关键任务 |
|
||||
|
||||
## API 接口
|
||||
|
||||
| 接口 | 方法 | 权限节点 | 说明 |
|
||||
|------|------|---------|------|
|
||||
| `/job/page` | GET | `sys:job:page` | 任务分页列表 |
|
||||
| `/job/detail/<int:id>` | GET | `sys:job:detail` | 任务详情 |
|
||||
| `/job/add` | POST | `sys:job:add` | 新增任务 |
|
||||
| `/job/update` | PUT | `sys:job:update` | 编辑任务 |
|
||||
| `/job/delete/<int:id>` | DELETE | `sys:job:delete` | 删除任务 |
|
||||
| `/job/status` | PUT | `sys:job:status` | 启停任务 |
|
||||
| `/job/run` | POST | `sys:job:run` | 立即执行 |
|
||||
| `/job/log/page` | GET | `sys:jobLog:page` | 执行日志 |
|
||||
|
||||
## 分布式锁
|
||||
|
||||
多实例部署时,定时任务可能重复执行。项目通过 Redis 分布式锁解决:
|
||||
|
||||
```
|
||||
1. 任务触发时,先尝试获取 Redis 锁
|
||||
2. 获取成功 → 执行任务 → 释放锁
|
||||
3. 获取失败 → 跳过本次执行(其他实例正在执行)
|
||||
```
|
||||
|
||||
:::tip 锁的 Key
|
||||
分布式锁的 Key 格式为 `job:lock:{job_id}`,TTL 与任务执行超时时间一致。
|
||||
:::
|
||||
|
||||
## 总结
|
||||
|
||||
定时任务模块具备以下特点:
|
||||
|
||||
```
|
||||
1. APScheduler:基于成熟的调度框架,支持 Cron 表达式
|
||||
2. 动态管理:通过接口动态添加、修改、启停任务
|
||||
3. 执行日志:自动记录每次执行的开始时间、耗时、状态、异常
|
||||
4. 并发控制:可配置是否允许并发执行
|
||||
5. 错过策略:配置错过执行时的处理策略
|
||||
6. 分布式锁:多实例部署时避免任务重复执行
|
||||
7. 立即执行:支持手动触发任务立即执行
|
||||
```
|
||||
Reference in New Issue
Block a user