179 lines
6.8 KiB
Markdown
179 lines
6.8 KiB
Markdown
:::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. 立即执行:支持手动触发任务立即执行
|
||
```
|