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

5.8 KiB
Raw Blame History

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

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 > 0now() - last_run_at < min_interval_seconds → 跳过本次执行,推进 next_run_at,日志记录 skipped_interval
  3. 首次执行last_run_at IS NULL(从未执行)→ 跳过间隔检查,正常执行
  4. 强制执行force=true 参数绕过所有检查(并发 + 间隔),直接入队

间隔转换

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/schedulesPUT /api/schedules/{id} 请求体新增 min_run_interval_valuemin_run_interval_unitGET /api/schedules 响应新增 3 个字段。POST /api/schedules/{id}/run 新增 force 查询参数
前端 ScheduleTab 创建/编辑表单新增「最小运行间隔」配置行。列表新增「最小间隔」和「上次成功」列。手动执行确认框新增「强制执行」Checkbox
ETL 无影响。ETL 任务调度由 scheduled_tasks 表驱动,新增字段默认值 0 表示无限制,向后兼容
小程序 无影响
调度器 scheduler.pycheck_and_enqueue() 新增并发检查和间隔检查逻辑

回滚策略

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

-- 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 基线publicdocs/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
  • 后端 Schemaapps/backend/app/schemas/schedules.py
  • 前端组件:apps/admin-web/src/components/ScheduleTab.tsx
  • Spec.kiro/specs/admin-web-enhancement/
  • PRDdocs/prd/specs/P16-task-min-run-interval.md