Files
Neo-ZQYY/docs/database/BD_manual_scheduled_tasks.md
Neo 70324d8542 chore: 文档与 IDE 配置整理
- .kiro/specs/ → docs/specs/(41 个历史需求 spec 迁移,移除 .config.kiro)
- CLAUDE.md 三层拆分:根文件精简 + apps/backend/CLAUDE.md + .claude/commands/
- 新增 /spec-close、/pre-change 两个工作流命令
- DDL 基线刷新(从测试库重新导出 11 个文件,dws 35→38 表,biz 18→21 表)
- BD_Manual → BD_manual 命名统一(48 个文件)
- 修复 3 处文档与数据库不一致(auth.users.status 默认值、scheduled_tasks 字段、RLS 视图数)
- 新增 BD_manual_public_rbac_tables.md(public schema 8 张 RBAC/工作流表)
- 合并 biz.trigger_jobs 文档(10→12 字段,归档独立文档)
- docs/database/README.md 索引更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 00:02:37 +08:00

135 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BD 手册scheduled_tasks 新增字段P16 最小运行间隔)
## 概述
P16 为 `public.scheduled_tasks` 表新增 3 个字段,支持调度任务最小运行间隔机制。调度器轮询时检查并发状态和间隔约束,避免任务重复执行。
所有变更位于 `zqyy_app` / `test_zqyy_app` 数据库,`public` Schema。
## 变更原因
- P16 调度任务最小运行间隔需求:管理员可为每个任务配置最小间隔,任务即使调度到期也不会在间隔内重复执行
- 新增 `last_success_at` 字段区分"最后执行时间"和"最后成功时间",支持更精确的间隔计算
## 变更说明
| 库 | Schema | 表 | 变更类型 | 说明 |
|----|--------|---|---------|------|
| zqyy_app | public | scheduled_tasks | 新增字段 ×4 | min_run_interval_value, min_run_interval_unit, last_success_at, min_run_intervals |
---
## 新增字段明细
| 列名 | 类型 | 约束 | 默认值 | 说明 |
|------|------|------|--------|------|
| min_run_interval_value | INTEGER | NOT NULL | 0 | 最小间隔数值0=无限制,与现有行为完全一致) |
| min_run_interval_unit | VARCHAR(20) | NOT NULL | 'minutes' | 间隔单位:`minutes` / `hours` / `days` |
| last_success_at | TIMESTAMPTZ | — | NULL | 最后一次成功执行的时间 |
| min_run_intervals | JSONB | NOT NULL | '{}' | 每任务子代码级别的最小运行间隔配置key=task_code, value=interval_seconds |
### DDL
```sql
ALTER TABLE scheduled_tasks ADD COLUMN min_run_interval_value INTEGER NOT NULL DEFAULT 0;
ALTER TABLE scheduled_tasks ADD COLUMN min_run_interval_unit VARCHAR(20) NOT NULL DEFAULT 'minutes';
ALTER TABLE scheduled_tasks ADD COLUMN last_success_at TIMESTAMPTZ;
COMMENT ON COLUMN scheduled_tasks.min_run_interval_value IS '最小间隔数值0=无限制)';
COMMENT ON COLUMN scheduled_tasks.min_run_interval_unit IS '间隔单位minutes/hours/days';
COMMENT ON COLUMN scheduled_tasks.last_success_at IS '最后一次成功执行的时间';
```
---
## 业务逻辑
调度器(`scheduler.py`)轮询时对每个到期任务执行以下检查:
1. **并发检查**`last_status = 'running'` → 跳过本次入队,日志记录 `skipped_concurrent`
2. **间隔检查**`min_run_interval_value > 0``now() - last_run_at < min_interval_seconds` → 跳过本次执行,推进 `next_run_at`,日志记录 `skipped_interval`
3. **首次执行**`last_run_at IS NULL`(从未执行)→ 跳过间隔检查,正常执行
4. **强制执行**`force=true` 参数绕过所有检查(并发 + 间隔),直接入队
### 间隔转换
```python
def _convert_interval_to_seconds(value: int, unit: str) -> int:
multipliers = {"minutes": 60, "hours": 3600, "days": 86400}
return value * multipliers.get(unit, 60)
```
### last_success_at 更新规则
- 任务成功完成时:`last_status='completed'`, `last_success_at=NOW()`
- 任务失败时:`last_status='failed'``last_success_at` 不变
---
## 兼容性
| 组件 | 影响 |
|------|------|
| 后端 API | `POST /api/schedules``PUT /api/schedules/{id}` 请求体新增 `min_run_interval_value``min_run_interval_unit``GET /api/schedules` 响应新增 3 个字段。`POST /api/schedules/{id}/run` 新增 `force` 查询参数 |
| 前端 ScheduleTab | 创建/编辑表单新增「最小运行间隔」配置行。列表新增「最小间隔」和「上次成功」列。手动执行确认框新增「强制执行」Checkbox |
| ETL | 无影响。ETL 任务调度由 `scheduled_tasks` 表驱动,新增字段默认值 0 表示无限制,向后兼容 |
| 小程序 | 无影响 |
| 调度器 | `scheduler.py``check_and_enqueue()` 新增并发检查和间隔检查逻辑 |
## 回滚策略
```sql
BEGIN;
ALTER TABLE scheduled_tasks DROP COLUMN IF EXISTS min_run_interval_value;
ALTER TABLE scheduled_tasks DROP COLUMN IF EXISTS min_run_interval_unit;
ALTER TABLE scheduled_tasks DROP COLUMN IF EXISTS last_success_at;
COMMIT;
```
注意:
- 回滚后所有任务恢复为无间隔限制的行为
- 回滚前需确认后端代码已移除对这 3 个字段的引用
- `last_success_at` 数据丢失不可恢复
## 验证 SQL
```sql
-- 1. 验证新增字段存在且类型正确
SELECT column_name, data_type, column_default
FROM information_schema.columns
WHERE table_name = 'scheduled_tasks'
AND column_name IN ('min_run_interval_value', 'min_run_interval_unit', 'last_success_at');
-- 预期3 行
-- min_run_interval_value | integer | 0
-- min_run_interval_unit | character varying | 'minutes'::character varying
-- last_success_at | timestamp with time zone | NULL
-- 2. 验证现有任务的新字段默认值
SELECT id, name, min_run_interval_value, min_run_interval_unit, last_success_at
FROM scheduled_tasks
LIMIT 5;
-- 预期min_run_interval_value=0, min_run_interval_unit='minutes', last_success_at=NULL除非已手动配置
-- 3. 验证已配置间隔的任务数量
SELECT COUNT(*) FROM scheduled_tasks WHERE min_run_interval_value > 0;
-- 预期:≥ 0初始状态为 0配置后递增
-- 4. 验证字段注释
SELECT col_description(
(SELECT oid FROM pg_class WHERE relname = 'scheduled_tasks'),
(SELECT attnum FROM pg_attribute WHERE attrelid = 'scheduled_tasks'::regclass AND attname = 'min_run_interval_value')
);
-- 预期:'最小间隔数值0=无限制)'
```
## 关联文件
- DDL 基线public`docs/database/ddl/zqyy_app__public.sql`
- 迁移脚本:`db/zqyy_app/migrations/2026-03-22__p16_min_run_interval.sql`
- 调度器逻辑:`apps/backend/app/services/scheduler.py`
- 后端路由:`apps/backend/app/routers/schedules.py`
- 后端 Schema`apps/backend/app/schemas/schedules.py`
- 前端组件:`apps/admin-web/src/components/ScheduleTab.tsx`
- Spec`.kiro/specs/admin-web-enhancement/`
- PRD`docs/prd/specs/P16-task-min-run-interval.md`