:::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/` | GET | `sys:job:detail` | 任务详情 | | `/job/add` | POST | `sys:job:add` | 新增任务 | | `/job/update` | PUT | `sys:job:update` | 编辑任务 | | `/job/delete/` | 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. 立即执行:支持手动触发任务立即执行 ```