# data-scheduling-platform **Repository Path**: hwxus/data-scheduling-platform ## Basic Information - **Project Name**: data-scheduling-platform - **Description**: 基于 Apache SeaTunnel 2.3.13 的表级全量/增量同步图形化调度平台(本地单机部署),支持 PostgreSQL / MySQL / Oracle / MongoDB 四库任意组合互同步,提供任务配置、调度、监控、对账的完整工作流。 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 5 - **Forks**: 2 - **Created**: 2026-08-12 - **Last Updated**: 2026-10-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: WorkBuddy, Python, FastAPI, Postgresql, seatunnel ## README # 数据库同步 GUI 调度平台 基于 **Apache SeaTunnel 3.0.0** 的表级全量/增量同步图形化调度平台(本地单机部署),支持 PostgreSQL / MySQL / MariaDB / 达梦 DM8 / MongoDB / Redis / Easysearch(Elasticsearch 兼容)以及 **Oracle(待适配)** 八库组合同步,提供任务配置、调度、监控、对账的完整工作流。 ## 功能特性 - **八库互通**:PG / MySQL / MariaDB / Oracle / 达梦 DM8 / MongoDB / Redis / Easysearch 之间的表级同步,全量 + 增量(CDC)全覆盖(Oracle 待适配,Easysearch / 达梦 仅全量) - **整库同步(v0.15,范围 v0.25 收窄为「同库型」)**:单任务一键同步源库全部表(支持表名关键字过滤),运行时动态发现表清单、单作业多表并行抽取写入,目标表由引擎按源结构自动创建(达梦目标由平台逐表预建);**仅支持同库型之间**(source.type == target.type,如 PG→PG、达梦→达梦,不区分版本),支持 PG/MySQL/MariaDB/达梦 关系型同库型库对库(全量 + insert/overwrite;Oracle 待适配) - **增量 CDC**:PostgreSQL 逻辑复制、MySQL/MariaDB Debezium、MongoDB ChangeStream,含断点续传(Savepoint);Oracle 待适配;Redis / Easysearch / 达梦 仅全量(引擎无 Dameng-CDC 源连接器,3.0.0 连接器清单亦无,增量仅 timestamp 轮询降级) - **CDC 管理**:作业暂停(保留位点)→ 恢复(无丢失无重复续跑)→ 终止,以及 DDL 变更流程;列表新增「位点」列——源库实时位点由后端后台循环(`position_fetcher.position_refresh_loop`,v0.51)周期性采集写库,列表直读元数据,**该列在 v0.51 之前恒为空**;**资源回收语义(v0.51 T68)**:硬终止/删除时统一清理 PG 复制槽与 SeaTunnel savepoint,优雅暂停(paused)则两者全保留以便恢复 - **可视化编排**:四步向导创建任务(源/目标/字段映射/模式参数),字段同名自动匹配;MongoDB 嵌套结构展平预览;源表 WHERE 条件过滤;任务名称根据源/目标类型简称自动生成;字段映射表新增「目标类型」列(v0.57),仅时间类源列(`timestamp`/`datetime`/`date`/`time`)可显式指定原生 `TIMESTAMP`/`DATE`/`TIME` 类型,消除 MySQL 源时间列默认落 TEXT 且带 `+08` 时区后缀的残留 - **自动建表**:内置类型映射矩阵,目标表不存在时按字段映射自动生成 DDL 建表(与数据同步解耦,幂等);`overwrite` 重跑结果不叠加;**v0.49 结构同步完善**:字段注释/默认值可随结构同步(`sync_comments` / `sync_defaults` 开关)、二级索引默认不建(运行弹窗勾选才建)、源表主键继承为目标主键(跨库主键/索引列名按库规则折叠大小写)、跨库默认值安全透传(时间函数默认值仅落原生时间列,规避 MySQL 1067) - **任务管理**(已完成 v0.42,将原「同步任务」与「调度管理」合并):四步向导创建任务;**调度下沉为任务属性**——行操作「配置调度」直接配 Cron 定时(支持秒级)、失败重试次数/间隔、超时、启用开关,弹窗内实时显示 Cron 中文释义;列表默认展示「任务名称 / 源 / 目标 / 模式 / 写入 / 状态 / 执行状态 / 更新时间」等 11 列(默认列可整体经「列设置」调整;「调度类型 / Cron 表达式 / 下次执行 / 调度状态」四列**默认隐藏**,避免手动任务场景空列占宽)与调度筛选;列表「最新执行」按 `start_time DESC` 精确取最新(v0.51 修复原 `max(id)` 非时间序取错的问题),累计写入经 30s TTL 缓存并依托 `idx_exec_task_start` 复合索引;任务列表**批量运行限并发提交(并发 4、单次上限 10 个,v0.21)**,防止大批量同步写库误操作 - **实时监控**:执行状态与指标由前端轮询实时刷新(HTTP REST,无 WebSocket 长连接);运行中任务的实时写入行数由引擎指标提供——v0.51 修复读取端点(`job-metrics` 对流式作业恒返回 204 空 → 改用 `job-info` 顶层 `metrics`),此前 running 行的进度长期取不到值 - **执行历史**:指标、增量位点、对账结果,成功/失败均可查看引擎执行日志(UTF-8/GBK 容错解码,**v0.51 起默认全量返回**,不再默认只取尾部 800 行,「复制日志」复制全部内容);日志无 jobId 匹配时按执行时间窗口回退;列表显示源→目标数据源名称;**按筛选条件导出 CSV/Markdown 报告(含指标与对账,2026-08-22 T7)** - **数据对账**:全量同步完成后自动源/目标行数校验(PG/MySQL/MongoDB,按 WHERE 口径) - **数据质量(v0.53 落地,v0.54 Phase 3 闭环)**:新增「**质量体检**」独立模块——SQL 直查采样 + 元库阈值规则 + 复用既有通知渠道,覆盖**表级体检 / 字段级规则 / 项目级跨表一致性**,内置 **12 条只读校验规则**(行存在性/行数下限/空值率/主键空值/主键重复/唯一性/数值区间/枚举集中度/时效新鲜度/跨表外键一致性/长度合规/枚举白名单),按**完整性 / 准确性 / 一致性 / 及时性四维加权(30/30/20/20)**输出综合分与分级(PASS≥90 / WARN 80–89 / FAIL<80),前端「质量看板」含四维条形图与趋势折线;独立 `/quality/*` API 与 `etl.tb_quality_*` 六表,不占引擎资源池、不侵入既有同步链路(方案见本地 `docs/数据质量模块设计方案.md`);**v0.54 Phase 3 闭环**:质量告警按实例**聚合成一条**经 Webhook(企业微信 / 钉钉 / 飞书)外发(新增「质量体检告警」开关)、质量任务 Cron **定时调度真正生效**(新增前端配置入口)、单实例**报告导出**(CSV 明细平表 / Markdown 报告,前端两处入口),并修订评分语义——**执行异常(ERROR)不再与不达标(FAIL)同记 0 分**(现与「跳过」等价、不参与评分,避免瞬时故障误判);**仪表盘已集成质量体检核心指标**(v0.55,主仪表盘右栏「质量体检」卡片:最新体检的综合分/分级、四维分值、通过/警告/不达标/执行异常计数与 ⚠ 执行异常维度提示,独立取数、失败静默降级);**v0.55 支持自定义规则**——管理员可创建自定义 SQL 模板的质检规则(SQL 安全校验:禁止危险关键字/分号/注释,仅允许 SELECT),内置规则不可修改/删除 - **数据源管理**:八库 CRUD(含 Easysearch/Elasticsearch/达梦 DM8),新建必须先通过连接测试(v0.3),密码 AES-GCM 加密存储;新建时名称自动生成(类型_主机_端口/库名,MongoDB 从 uri 提取主机、Oracle 用 service_name、达梦用用户/schema 名);列表显示类型色点、连接信息(MongoDB 展示脱敏 uri)、连通性状态;多选筛选 - **文件导入导出**:Excel 导入(解析/类型推断/自动建表/写入)与导出(v0.5),支持 PG/MySQL/MariaDB/MongoDB/Redis/达梦 DM8(Easysearch 暂不支持) - **通知告警**:**Webhook 告警**(企业微信/钉钉/飞书/自定义)单通道(邮件 SMTP 通道已于 v0.18 下线),任务失败 / 对账 diff / CDC 异常 / 质量体检不达标触发;失败任务的**桌面/Windows 通知**由前端轮询执行状态触发浏览器 Notification(需在设置页授权);**告警抑制(v0.61)**——按「事件类型 + 任务」指纹冷却(默认 1800s 可配)去重,失败执行标记「已处理 / 忽略」后对该任务**持续静默直到恢复**,恢复时发「已恢复」通知并自动解除;**任务级失败自动暂停(v0.61,默认关闭)**——按调度周期统计连续失败,达阈值自动停用任务并记录原因(手动运行不计入、CDC 排除) - **多 Worker 水平扩展(v0.69~v0.72,Phase 0~3,**v0.74 起默认 `WORKERS_MODE=multi`**)**:单机多进程 `uvicorn --workers N`(**N=2 起步,扩容只改启动参数**)——PG advisory lock **单 leader** 调度(Cron 不重复触发、leader 失联快速接管)、monitor lease **认领队列**(同一执行恒单 owner,异常接管不重复监控/结算)、告警抑制/静默以元库 `tb_alert_suppress` 为**跨进程事实源**(冷却窗口与「已处理」静默跨 worker 生效);回滚开关 `single` 永久保留(`.env` 改回 `single` 重启即回单 worker 语义,行为与 v0.73 及以前一致);连接池按 `N × (DB_POOL_SIZE + DB_MAX_OVERFLOW) ≤ max_connections` 核算(不引入 PgBouncer/Redis,上云/容器/HA 多副本不在范围)。部署口径详见 `docs/部署运维手册.md` §3.2 - **用户管理**:管理员专属,批量录入/重置密码/启停/角色(保护规则:不能删自己、至少保留一名管理员) - **列表体验增强(v0.17)**:所有列表表格**表头居中**;时间字段**全局支持排序**,整表默认按「更新时间倒序」排列(无更新时间则取结束时间 > 创建时间兜底),后端经通用 `apply_sort` 辅助 + `sort_by`/`order` 参数实现;执行历史 / CDC / 调度 / 同步任务 / 数据源 五个重表新增「**列设置**」面板,可勾选显隐字段(localStorage 按表持久化),默认展示精简字段集、序号/选择/任务(执行ID)/操作 等关键列锁定常显 - **性能**:并行分片 + 批量读写,100 万行全量同步约 33s(3 万行/s);PG→MySQL 约 4 万行/s,PG→MariaDB 约 4.1~4.8 万行/s(2026-08-22),MariaDB→PG CDC 增量约 9.3 千行/s;MongoDB sink 调优后(`bulk.size=2000`)约 1.3 万行/s(2026-08-22,较调优前 +75%);**页面/列表加载(v0.51 T67)**:任务管理列表累计写入聚合 108ms→30.5ms(30s TTL 缓存 + `idx_exec_task_start` 复合索引)、仪表盘统计 15s 进程内 TTL 缓存、执行历史引擎指标缓存 5s→10s 与前端轮询节奏对齐、全屏遮罩收敛为内容区局部 loading(含 8s 超时兜底);**列表关键字模糊搜索(v0.52)**:`tasks` / `datasources` / `users` / `files` 的 `ILIKE '%kw%'` 改走 pg_trgm GIN 索引(共 5 条),避免全表扫描 - **元数据缓存(v0.21)**:表浏览/取字段接口进程内 60s TTL 缓存,降低向导与运行预处理重复查询成本;数据源更新/删除、建表、补列等 DDL 后主动失效;MongoDB 字段采样与整库动态发现不走缓存(详见本地 `docs/历史方案归档.md §一`) - **已实测链路**:PG→PG/PG→MongoDB/PG→MySQL 全量、MySQL→PG CDC(含 Savepoint 暂停恢复)、MongoDB→PG/MariaDB 全量(754 条幂等重跑)、Redis→MariaDB 全量、MongoDB→Redis(754 条含中文,2026-08-17 引擎 UTF-8 修复后)、**PG→PG 整库同步(whole-db,跨库自动建 schema + 20 万行 2 表幂等重跑,2026-08-21)**、**达梦 DM8 全量双向(PG↔DM insert/upsert/overwrite,2026-09-02 端到端 5/5)**、**PG→MariaDB 全量三档(100 万行,41k~48k 行/s,2026-08-22)+ MariaDB→PG CDC 增量(binlog ROW,50 万行 9.3k 行/s,2026-08-22)**、**Easysearch→PG 全量(HTTPS+basic auth,3 文档端到端,2026-08-23)**、**DM→PG 全量(2026-09-08,v0.49:修复源列探查误传密文、PG 目标列名小写归一、目标表主键同步后打通)**、**DM→DM 整库 overwrite(v0.50.1:修复 sink 缺 query 缺陷,N3b 达梦侧实跑幂等,3 表 3/2/2 全对账)**、**MySQL→MySQL 整库 overwrite(v0.50.1:二阶幂等验证,引擎 DROP_DATA 正常生效,7 行不叠加)**、**完整四库矩阵(PG→DM / PG→MySQL / PG→Mongo / PG→PG)全绿(2026-09-09 v0.50.1 回归)** ## 已知限制与能力校验(SeaTunnel 3.0.0 逐行复验结论 + 2.3.13 历史实测,2026-08-18 / 2026-08-22 / 2026-09-12 / 2026-10-04 更新) > **引擎升级注(2026-10-02)**:本机引擎已升级 **Apache SeaTunnel 3.0.0(JDK 21)**,安装目录 `D:\App\apache-seatunnel-3.0.0`(原 2.3.13 目录保留)。升级当日已实证:平台切改后 `-m live` 7/7、UI 全量 233/0/8、默认门禁 747/0/34、集群双成员、REST 概览 `projectVersion: 3.0.0`。**下表各行仍为 2.3.13 实测口径**(升级前事实,按「历史表述不回改」保留);3.0.0 逐条复验已拍板**另立一批快验**(抽本机可行项:PG timestamptz 快照、Mongo 嵌套展平、MySQL 目标 upsert 经引擎、Redis sink 中文编码——T15-② MariaDB overwrite 因本机已换装 MySQL 5.7、达梦行因 DM8 离线标记为不可复现项),结论回填本注后下表方可作 3.0 结论引用。 > **快验结论回填(2026-10-03,SeaTunnel 3.0 快验批)**:四项抽验**全过**(3.0.0 实测)——① PG `timestamptz` 快照 success(无 `TIMESTAMP_TZ` Unsupported 报错,5 行时区归一、目标列按 type_mapper 折叠 TEXT);② MongoDB 嵌套字段展平 success(`addr.city → addr_city` 展平 5/5 + 数值列真类型非字符串);③ MySQL 目标 upsert 两轮 success(3 → 4 行、改源生效、幂等,`id1='一改'`);④ Redis sink 中文 success(3 键 `qv30_cn:*` 中文 + emoji 无损 UTF-8)。**T15-② MariaDB overwrite 与达梦行维持「本机不可复现」**(已换装 MySQL 5.7 / DM8 离线)。快验伴生修复三缺陷(`BUG-20261003-02` TEXT 主键建表 1170、`BUG-20261003-03` PG→Redis 数值列 ClassCastException、`BUG-20261003-04` MySQL 中文列 latin1 1366;均已随 v0.77 发布)+ 1 观察项(Redis 目标不强制主键 → 同键静默覆盖,入册排期观察项)。**回填后效力**:上列①~④四项可作 3.0.0 结论引用;**未抽验的表行维持 2.3.13 实测口径**(历史表述不回改,如需 3.0 结论须另行抽验)。 > **三修端到端归真(2026-10-04)**:对 10-03 三修做**无夹具**复跑归真,三项全过(3.0.0 实测)——R1 ③ MySQL upsert 改走平台新建表(DDL 自带 `utf8mb4`,中文两轮幂等 `exe_2ac8f3f6339f`/`exe_fffadfae4c72`)、R2 ④ Redis sink 改用列 API 真类型名(`integer`/`timestamp with time zone`/`text` 分族正确,`exe_a96cccf5f91f`)、加验 TEXT 主键→MySQL 自动建表(`VARCHAR(255)` 主键 + utf8mb4 无 1170,`exe_fc6a95b79c02`)。归真期间发现并修复 `BUG-20261004-01`(引擎 URL `characterEncoding` 用了非法 Java 编码名,已随 v0.77 发布)。 > **逐行复验回填(2026-10-04,3.0 已知限制表逐行复验批,深度 A)**:对下表 19 行中本机可行项完成 **P1~P8 逐行复验**(驱动 `scripts/tmp/qv31.py`,P 清单结果与证据锚点见排期变更记录 2026-10-04 二次)——**复验通过**:PG CDC 主链(RI 拦截→FULL→INSERT/UPDATE/DELETE 三连→停止回收)、**timestamptz 3.0 已支持(2.3.13 TIMESTAMP_TZ Unsupported 限制消失)**、Mongo ChangeStream 主链(rs0 快照 5/5+插入捕获)、字段重命名、缺列 ALTER ADD、JSON/JSONB/UUID 降级双源、时间列 1067 守卫、拦截三连(Redis 增量/upsert 主键/整库同库型)、savepoint 清理与发布回收;**正向变化**:MySQL 源时间列 `+08` 时区后缀 3.0 消失。**5 个缺陷候选已入册候选池(未编号,修复批按「修复提交日」取号)**:D-A T65 同名 target_type 尊重修复被 v0.46 重构覆盖丢失、D-B 显式原生时间列 3.0 varchar 绑定失败、D-C MySQL 源时间值保真(DATE 2/5 错乱、TIME 带当天日期)、D-D T39 复制槽 stop 后 3/3 残留、D-E Mongo CDC `float` 类型映射缺失(默认路径 EJSON 信封绑定失败)。**修复批收口(2026-10-04 当日)**:五候选全部按拍板顺序转入修复并编号 `BUG-20261004-02~06`(D-A→-02、D-E→-03、D-D→-04、D-B→-05、D-C→-06),四线 e2e(pe1/pe2/de1/p1)全绿、pytest 757→777,**已随 v0.78 发布**(详见 `CHANGELOG §[v0.78] › Fixed` 与缺陷索引)。**同族回归扫补号(2026-10-04 四次批)**:`BUG-20261004-07`(PG 源 date/time/interval 统一 `to_char` 值错乱,D-C 的 PG 侧平行面)已修、`e1` e2e 全绿待发;MySQL CDC(binlog)时间列矩阵 e2e 全绿——DATE/TIME(6)/DATETIME(6)/TIMESTAMP(6) 微秒与跨日边界逐列等源、原生绑定正常,**CDC 路径无同族缺口**。**下表新增第 4 列逐行标注本批结论**;未复验行维持 2.3.13 口径(历史表述不回改)。 平台在**任务创建/编辑/运行前**统一拦截并给出明确提示(`validate_sync_capabilities`),避免同步运行时才报错: | 限制 | 引擎原因 | 平台行为 | 3.0.0 逐行复验结论(2026-10-04) | |------|----------|----------|------| | MariaDB 目标 `upsert` | ~~2.3.13 无 MariaDB 方言~~ **已解决(2026-08-22)**:job_builder 对 MariaDB 改用 MySQL 官方驱动 + `jdbc:mysql://` URL 走 MySQLDialect(MariaDB 协议兼容),`ON DUPLICATE KEY` 实测可用 | **拦截已解除(T15-①)**,向导可选 upsert(需指定主键);实测 1000 行重跑幂等 + 更新生效 | 不可复现(本机 MariaDB 已换装 MySQL 5.7,T15-① 结论维持) | | MariaDB 目标 `overwrite` | MySQL 方言 SaveMode 版本解析拒绝 MariaDB 版本串(DROP_DATA 失败) | 提交前平台主动清空目标表(TRUNCATE,失败回退 DELETE)+ sink 走 APPEND_DATA,保证幂等 | 不可复现(T15-② 维持观察,本机无 MariaDB) | | MariaDB 目标自动建表(平台 DDL 方言) | 无(引擎无关)——平台自身 `generate_ddl` 方言分支漏判 mariadb,误发 PG 专属 `COMMENT ON TABLE` 语法 | **已修复(v0.42)**:方言分支统一 `in ("mysql","mariadb")` + 预览/实建共用 `build_target_ddl_for_task` + `_assert_dialect_safe` fail-fast 拦截错方言语法(案例 `pg2mariadb_tb_api_access_log`) | 平台侧缺陷(v0.42 已修),与引擎版本无关,无需复验 | | MariaDB 源 CDC | MySQL-CDC 初始化解析 GTID 时,MariaDB `0-1-N` 格式 `GtidSet` 解析必炸 | 前置:`RESET MASTER` 清空 GTID 后启动任务(**任务启动后不得重启**);binlog 需开启 ROW 格式(配置须置于 my.ini `[mysqld]` 段) | 不可复现(本机已换装 MySQL 5.7) | | MySQL 源/目标(非标准版本串,如 26.7.0) | 2.3.13 `MySqlVersion.parse` 仅识别已知版本号,MySqlCatalog 对未知版本抛 `UnsupportedOperationException` 后**自动回退 V_5_7 方言**(作业 INFO 日志含堆栈,非阻断;2026-08-26 实测 MySQL 26.7.0) | 无需处理:自动建表 DDL、upsert(ON DUPLICATE KEY)、全量(100 万行)、CDC I/U/D(GTID=ON)均实测正常;MySQL/MariaDB 源 CDC 运行前 binlog 预检(T42)会在配置不合规时给出修正 SQL | 未复验(本机 MySQL 5.7 为标准版本串,2.3.13 回退结论维持) | | PG 源 CDC(2026-08-25 实测打通 PG→PG 跨库) | ① 源表须 `REPLICA IDENTITY FULL` 否则 UPDATE/DELETE 无法捕获;② 引擎不支持 `timestamptz` 反序列化(TIMESTAMP_TZ Unsupported) | `REPLICA IDENTITY` 不合规:平台运行前预检(T38)**直接拦截**并给修正 SQL;`timestamptz` 列:平台运行前预检(T38/T44)改为**软告警兜底(不阻断提交)**,任务仍可运行,运行期若引擎报 TIMESTAMP_TZ Unsupported 再提示,建议表结构改用 `timestamp`;CDC 停止后平台自动清理 `seatunnel_` 复制槽与 `dbz_publication`(T39,防 WAL 涨盘),无需手动清理 | 逐行复验 P1/P1b:① RI FULL 仍必需——预检拦截+修正 SQL 实测(`exe_97a43d29c307` 失败形状);② **timestamptz 3.0 已支持**——TIMESTAMP_TZ Unsupported 限制消失(软告警放行、快照+CDC 落地 `exe_555ddb5b410d`);③ 发布回收 ✓、**复制槽 stop 后回收 ✓**(D-D 已修 `BUG-20261004-04`:DROP 3 次重试 + 槽不存在幂等跳过 + 耗尽升 warning,`p1` stop 后 `slots=[] pubs=[]` 双回收) | | Oracle 源/目标(全量 + CDC,**待适配**) | SeaTunnel Oracle-CDC 基于 Debezium+LogMiner,需 DBA 前置(`ARCHIVELOG` 归档 + 最小补充日志 + LogMiner 权限账号) | 平台侧适配代码与运行前预检(T43)保留,实例级验证待本机 Oracle + `ojdbc8.jar` 就绪后执行(恢复清单 D1/D3/D4);受限时可降级 timestamp 轮询 | 待适配(维持,未复验) | | MongoDB 源 CDC(ChangeStream,2026-08-25 实测打通 Mongo→PG) | ① standalone 不支持 ChangeStream,需单节点 replica set;② 非 `_id` 数值字段经 sink 序列化为 BSON 包装串(如 `{"_value":{"$numberInt":"1"}}`),与 `_id` 包裹同根因 | 前置:mongod 启用 `replication.replSetName: rs0` 并 `rs.initiate()`;数值字段落关系型目标此前建议存字符串——平台现已自动 CAST 兜底(T40),无需存字符串 | 逐行复验 P3/P3b:rs0 ChangeStream 主链 ✓(快照 5/5+插入捕获 `exe_600f27f01545`);数值列默认类型路径**已修复**——cols `float`/`int64` 兜底声明 string → EJSON 信封绑定失败已定因(`BUG-20261004-03` D-E:CDC/batch/目标/null-transform 四表 + `type_mapper` 补 `str/float/bigint/int64` 兼容键、`_bson_type_name` 对 `Int64` 实例归一 `bigint`,`de1` 平台 e2e 目标 `price double precision / big bigint` 原生数值无信封 ✓;T40 引擎侧 3.0 回归通过) | | 嵌套字段展平映射(`a.b`→`a_b`) | MongoDB 源将嵌套文档读为 row 类型,需 `sql` transform 以 `address.city` 取子字段展平 | **已解决(T16-①)**:MongoDB 源 + 关系型目标(全量)经 `sql` transform 展平并重命名,本机实测可用(2026-08-22);关系型源 / Mongo→Mongo 等组合仍运行前拦截 | 3.0 ✓(10-03 快验:addr.city 展平 5/5) | | 字段重命名(target≠source) | generate_sink_sql 按目标列名生成 INSERT,源字段名不匹配 | **已解决(T16-②)**:全量 + 关系型目标(非 Redis)经 FieldMapper transform 改写列名,本机实测可用(2026-08-22) | 3.0 ✓(P4,`exe_285c66602c45`,user_name→uname 3 行) | | 目标表缺列(旧表结构不匹配) | INSERT 引用不存在列 | **已解决(T16-③)**:运行前/上报前平台主动 `ALTER ADD COLUMN` 补齐,本机实测可用(2026-08-22) | 3.0 ✓(P5,`exe_75e8dd8e9385`,运行前 2 列→ALTER ADD 补齐带数据) | | Redis / Easysearch 源或目标增量/CDC | Redis 无日志/时间戳能力,Easysearch 无 binlog/changeStream | 创建/编辑时拦截,仅支持全量 | 3.0 ✓(P8:Redis 增量创建期 code 1001 拦截实测;Easysearch 同口径未单独复验) | | 达梦 DM8(全量 + 关系型目标) | ① 引擎 2.3.13 无 Dameng-CDC 源连接器,增量仅 timestamp 轮询降级;② overwrite 时引擎 DROP_DATA 为空操作(catalog 查不到表→跳过清空);③ 引擎 catalog 无自动建表能力,整库目标需平台逐表预建;④ catalog 建表不可用,表名须归一大写(`database` 字段 = schema);⑤ **generate_sink_sql=True 时引擎生成 `MERGE INTO USING (SELECT ? "col"...`,达梦 JDBC 不支持 `? "column"` 语法(报错 -2007);⑥ generate_sink_sql=False 时引擎 catalog 发现表走 JDBC DatabaseMetaData,Dameng 驱动该 API 有缺陷(直接 SQL 查 ALL_TABLES 正常,但 DatabaseMetaData 返回空);⑦ **generate_sink_sql=False + query 后,SinkWriteCount>0 / SinkCommittedCount=0,真因:平台 query 列名随源小写,但达梦 CASE_SENSITIVE=1 目标表大写列 NOT NULL,小写列可空,导致大写列落空触约束**;⑧ Dameng 表存在大小写重复列(历史遗留问题,导致 getTable 返回列数翻倍)** | ① 创建/编辑期拦截 cdc-initial/cdc-latest,仅 timestamp 放行;② overwrite 提交前平台 TRUNCATE 兜底 + sink APPEND_DATA,重跑幂等;③ 整库(同库型 DM→DM)目标由平台逐表 `generate_ddl` 预建 + TRUNCATE;④ 达梦目标统一 `schema_save_mode=IGNORE`,由平台 dmAsync 预建大写表;⑤ **平台侧对 dameng 强制设置 generate_sink_sql=False**;⑥ **源码修改 `DamengCatalog.getTable()`(JOIN USER_INDEXES 修复),JAR 已部署(2026-09-07)**;⑦ **已修复(2026-09-07)**:平台 query 列名统一大写 `f'"{c.upper()}"'`;⑧ **已修复(2026-09-07)**:`SELECT_COLUMNS_SQL` 去重子查询过滤小写重复列;⑨ **DM 作为 source 时(v0.49)**:SeaTunnel 2.3.13 `JdbcSource` 初始化会经 `DamengCatalog.open()` 额外开 JDBC 会话探测表结构,该会话报「登录失败次数超过限制」触发 API-06 `Unable to create a source for identifier 'Jdbc'`——平台改为走 `_dameng_source_select_exprs` 直接构建 SELECT 表达式绕过 catalog 探测(与源列类型探查改用 `DataSourceConn.password` 明文配套修复) | 不可复现(DM8 离线,维持) | | 跨库时间列默认值(v0.49) | 平台 type_mapper 默认把各源时间列统一折叠为 **TEXT**(存 ISO 字符串规避精度丢失),若把源列时间函数默认值(`now()` / `CURRENT_TIMESTAMP`)原样拼进 TEXT 目标列,MySQL 会报 1067 `Invalid default value` | **已修复(v0.49)**:`_safe_default_expr()` 仅在目标列为**原生时间类型**时才透传时间函数默认值并按目标方言归一(MySQL/MariaDB→`CURRENT_TIMESTAMP`;PG/Oracle/达梦保留),落在非时间目标列一律丢弃;PG cast 语法字面量(`'x'::type`)仅 PG 目标保留 | 3.0 ✓(P7c:MySQL 目标 TEXT+1067 守卫过,列级默认值守卫不含表选项);伴生 3 缺陷候选**已同批修复(2026-10-04,已随 v0.78)**——D-A 同名 target_type 尊重丢失(`BUG-20261004-02`)、D-B 显式原生时间列 varchar 绑定失败(`BUG-20261004-05`)、D-C MySQL 源 DATE 2/5 错乱·TIME 带当天日期(`BUG-20261004-06`,按源类型格式化保值真);**+08 后缀 3.0 消失** | | 目标表 `upsert` 的前置条件 | 引擎 JDBC sink 的 upsert 依赖目标表**唯一约束/主键**;无主键表只能 overwrite | 平台建表时同步源表主键(T56);创建/编辑期对无主键源表 + upsert 组合给出提示 | 3.0 ✓(P8:upsert 无主键创建期 code 1001 拦截实测) | | PG 目标 JSON/JSONB/UUID 列(v0.43) | 引擎 2.3.13 JDBC connector 以 varchar 绑定写入,PG 不接受 varchar→jsonb/uuid 隐式转换 | 平台自动将 **PG 目标**的 JSON/JSONB/UUID 列降级为 **TEXT**(与源库型无关,MySQL/MariaDB/MongoDB 源同步到 PG 目标同样生效);TEXT 存 JSON 字符串,`SELECT`/`json` 访问完全兼容。MySQL/MariaDB 目标暂不降级(驱动行为不同) | 3.0 ✓ 双源(P6:MySQL 源 payload→TEXT `exe_bbe0a29edf00`、PG 源 jsonb/uuid→TEXT `exe_5851b9c5f294`;MySQL CHAR(36) 类型保真非降级对象) | | 整库同步仅限关系型**同库型**(source.type == target.type) | 跨库型(如 PG→MySQL)与 MongoDB/Redis 需逐集合采样字段定义、无统一表清单语义 | 创建/编辑时拦截,提示改用单表模式;整库仅支持全量 + insert/overwrite(无字段映射、无 upsert、对账标记 skipped) | 3.0 ✓(P8:跨库型创建期 code 3005「源=postgresql 目标=mysql」拦截实测) | | 列表关键字模糊搜索依赖 pg_trgm 扩展(v0.52) | 各列表页关键字走 `col ILIKE '%kw%'`(前导通配),B-tree 索引无法命中;改用 trigram GIN 索引提速 | 存量库执行 `backend/sql/migrate_v0.52_pg_trgm_search_indexes.sql`(内含 `CREATE EXTENSION IF NOT EXISTS pg_trgm`,**需 PostgreSQL superuser**);未安装时功能不受影响、仅退化为全表扫描。新库用 `full.sql` 已自动包含 | 平台侧扩展依赖,引擎无关,无需复验 | | CDC 资源回收依赖 `SEATUNNEL_HOME` 与状态存储类型(v0.51 T68) | 硬终止/删除 CDC 作业时会清理 PG 复制槽与 SeaTunnel savepoint 目录;savepoint 清理仅对 localfile 状态存储有效 | 需正确配置 `SEATUNNEL_HOME`(默认 Hazelcast IMap 无本地文件,自动跳过并记 WARNING,不影响停止/删除结果);复制槽清理仅 PG CDC 生效,其它源自动跳过 | 3.0 ✓(P1/P2):savepoint 清理 ✓(localfile 激活、job 目录 stop 后不存在)、发布回收 ✓、SEATUNNEL_HOME 生效、**复制槽清理已修复**(同 L43③,`BUG-20261004-04` D-D:3 次重试 + 幂等跳过 + 耗尽告警,`p1` stop 后槽/发布双回收) | > **排查规范**:碰到同步问题,若有目标表参与,**优先比对目标表实际字段与 SeaTunnel databaseTableSchema 返回的列**。差异在哪,问题就在哪。严禁在未确认目标表结构前猜测 JDBC/Dialect 层问题。 > 数据对账(全量后源/目标行数校验)仅 PG/MySQL/MongoDB 支持;Redis/Oracle 目标自动标记「跳过」。 > 完整记录见 `docs/遗留任务排期.md`(T15/T16)。 > 上述为平台能力边界(引擎约束);运行期故障排查与排错步骤见本地 `docs/故障排查FAQ.md`。 ## 技术栈 | 层 | 技术 | 说明 | |----|------|------| | 前端 | Vue 3 + Element Plus + Pinia + Vue Router | 9 个功能页 + 登录(侧栏:仪表盘 / 数据源 / 任务 / 历史 / CDC / 文件 / 质量 / 用户 / 设置) | | 后端 | Python FastAPI + SQLAlchemy 2 async + APScheduler | 任务编排 / 调度 / 监控 | | 执行引擎 | Apache SeaTunnel 3.0.0(Zeta,JDK 21) | 全量 JDBC/MongoDB/Redis + 增量 CDC | | 元数据库 | PostgreSQL | 独立 schema `etl`、`tb_` 前缀 | ## 架构 ``` Vue3 前端 (5173) │ HTTP REST(前端轮询) FastAPI 后端 (8000) —— 元数据存储:PostgreSQL(etl schema) │ SeaTunnel REST API(v2 / 8080) SeaTunnel Zeta 引擎 (8080 REST v2 · 5801 集群) —— 全量/增量同步执行 ``` ## 快速开始 **环境要求**:Java 21(SeaTunnel 3.0 引擎,启动脚本内置钉死 `D:\App\jdk-21.0.11.10-hotspot`,系统 `JAVA_HOME` 不被引擎依赖)、Python 3.12+、Node.js 20+、PostgreSQL 18、SeaTunnel 3.0.0。详细配置见 `docs/前置配置指南.md`。 ### 首次部署 ```bat :: 1. 初始化元数据库(建库后执行) psql -U -d -f backend\sql\init.sql :: 2. 配置后端(复制 .env.example 为 .env,填数据库连接) copy backend\.env.example backend\.env :: 3. 安装依赖(使用系统全局 Python / npm,无需虚拟环境) cd backend && pip install -r requirements.txt cd ..\frontend && npm install :: 4. 初始化 SeaTunnel(连接器 / JDBC 驱动 / REST / checkpoint,详见前置配置指南) ``` ### 日常启停(一键 bat 脚本) ```bat :: 一键启动(后端 8000 uvicorn --workers 2 + 前端 5173,自动打开浏览器;不含 SeaTunnel) :: 2026-09-29 起内部委托五合一 CLI 的 `dsp.bat up`(幂等跳过已在监听 · 按端口就绪等待 · 失败不开浏览器) 一键启动.bat :: 一键停止(终止后端与前端两个服务) 一键停止.bat :: 不想看到黑色控制台窗口 → 双击同名 .vbs 静默版(隐藏控制台跑上面两只 bat 的 /quiet 分支, :: 输出转 scripts\tmp\launcher.log | stopper.log,浏览器照常自启作为反馈) 一键启动.vbs 一键停止.vbs ``` **SeaTunnel 引擎需单独启动**:根目录 `一键启动.bat` 只拉起后端 + 前端;需要连引擎一起拉时用 `scripts\start-all.bat`(按序启动 **引擎 master(5801) → worker(5802) → 后端(8000) → 前端(5173)**,就绪轮询改判 **REST 8080**)与 `scripts\stop-all.bat`(按同四端口停止)。 > **2026-09-29 起四个 bat 全部委托五合一 CLI**:`一键启动.bat` 与 `scripts\start-all.bat` 的后端/前端改走 `dsp up`(引擎编排仍留在 `start-all.bat` 内),`一键停止.bat` 与 `scripts\stop-all.bat` 的后端/前端改走 `dsp down --yes`(树杀 + 端口复核),启动配方与杀进程逻辑只在 `scripts/dsp.py` 一处维护。 > **2026-09-29 起启动即挂自愈守护 `dsp watch`**:`dsp up` 默认顺带把守护拉到后台(`--no-watch` 关闭),每 5s 巡检 8000/5173,**掉线自动重新拉起**并记 `scripts/tmp/dsp_watch.log`;`dsp down --yes` **先收守护再杀端口**(pid 落 `scripts/tmp/dsp_watch.pid`)。手动:`dsp watch --detach`(后台常驻)/ `--once`(巡检一轮)/ `--stop`(收口)。 > **2026-09-30 起桌面零黑窗**:后端(uvicorn master + 2 worker)、前端与守护进程一律以 **`CREATE_NO_WINDOW` 隐藏控制台**后台运行,桌面上不会出现任何 `python.exe` / `node.exe` 窗口(修复 `BUG-20260930-01`:初版 `DETACHED_PROCESS` 使 master 无控制台,Windows 给每个 worker 各分配一个可见黑窗);配合 `.vbs` 静默启动器**全程无控制台窗口**、不会误触。 > **2026-09-27 起后端以 `uvicorn --workers 2` 启动**:v0.74 起 `WORKERS_MODE` 默认 `multi`,本机启动即目标多 Worker 形态;原 `--reload` 已移除(uvicorn 二者互斥,`reload` 开启时忽略 `workers`),改后端代码需手动停止+启动。 > **完整的部署步骤与全部启停脚本说明见 [部署运维手册](docs/部署运维手册.md) §二**(含 v0.51 引擎启停脚本固化说明),此处不重复。 访问 `http://127.0.0.1:5173`,默认账号 `admin / admin`(首次登录后请修改密码)。 > **注意**:`一键启动.bat` / `一键停止.bat` 均已委托 `dsp.bat` → `scripts/dsp.py`(Python 路径与服务启动配方 `service_spec` 在其中,改 `--workers`/端口只改一处);`scripts\*.bat` 中引擎相关仍硬编码 SeaTunnel 等安装路径,部署到其他机器需修改脚本内路径。 > **存量库升级**:按序执行 `backend/sql/migrate_*.sql`(自 v0.50.1 起新增 `migrate_v0.51_exec_task_start_index.sql` → `migrate_v0.52_pg_trgm_search_indexes.sql` → `migrate_v0.53_quality.sql` → `migrate_v0.54_quality_alert.sql` → `migrate_v0.56_quality_rule_dimension.sql` → `migrate_v0.61_t57_failover_alert_suppress.sql` → `migrate_v0.62_quality_rule_description.sql` → `migrate_v0.64_001_depends_on.sql` → `migrate_v0.65_001_alert_suppress.sql` → `migrate_v0.70_monitor_lease.sql` → `migrate_v0.71_exec_trigger_source.sql`);**v0.52 建 `pg_trgm` 扩展需 PostgreSQL superuser**(其余新增迁移普通权限即可)。新库直接用 `backend/sql/full.sql`(已含全部)。 > 部署前的完整配置(环境变量、元数据库、SeaTunnel 连接器/驱动/REST/checkpoint、CDC 前置)见 `docs/前置配置指南.md`。 ### 研发门禁与工具(`dsp`,T69 五合一 + T78 增补) ```bat :: 一键聚合(T78):scan → gate 按序、同一份汇总与单退出码(提交前首选单条) dsp check :: 代码 + 文档扫描(ruff + --fix 自动修 / ruff format report-only / vue-tsc / 死链 / 文档基线一致性)12 项,ALL PASS 才算通过 dsp scan :: 发版门禁(pytest 默认基线 + vite build 一键比对;--extras 附跑 live/dameng_live/multiworker) dsp gate :: 测试执行(先环境预检,再分组:--ui 全量回归 / --markers 另跑子集 / --report 落 junit+JSON) dsp test --env-only :: 发版预检(CHANGELOG [Unreleased] 结构 / 缺陷登记 / 版本头与公告)+ 拆段草稿(不落盘) dsp release --draft :: 服务启停与健康断言(up 顺带拉起自愈守护,down 先收守护再杀端口) dsp up && dsp status --require backend,vite && dsp down --yes :: 自愈守护单独操作:巡检一轮(--detach 后台常驻无窗口 / --stop 收口) dsp watch --once ``` > 全命令支持 `--json`,退出码 `0`=全绿 / `1`=有失败 / `2`=用法或环境错误;**完整参考见 [dsp 工具使用手册](docs/dsp工具使用手册.md)**(八子命令参数 + 五条场景流程 + 业界对照与改进候选),场景摘录另见 [贡献指南 §3](docs/贡献指南与开发规范.md)、[测试指南 §2.4](docs/测试指南.md)、[发版手册 §2](docs/发版手册.md)。 ## 界面预览 > 截图为 **2026-09-24 重摄**(`docs/screenshots/`,与侧栏 9 菜单对齐,含质量体检)。 | 仪表盘 | 数据源管理 | 任务管理(含调度配置) | |:-------|:-----------|:---------| | ![仪表盘](docs/screenshots/demo-dashboard.png) | ![数据源管理](docs/screenshots/demo-datasources.png) | ![任务管理](docs/screenshots/demo-tasks.png) | | ~~调度管理~~(已并入任务管理) | ~~运行监控~~(已下线,并入执行历史) | 执行历史 | |:-------|:-----------|:---------| | (已并入「任务管理」截图) | (已下线) | ![执行历史](docs/screenshots/demo-history.png) | | CDC 管理 | 文件导入导出 | 质量体检 | |:-------|:-----------|:---------| | ![CDC 管理](docs/screenshots/demo-cdc.png) | ![文件导入导出](docs/screenshots/demo-files.png) | ![质量体检](docs/screenshots/demo-quality.png) | | 用户信息 | 系统设置 | |:---------|:---------| | ![用户信息](docs/screenshots/demo-users.png) | ![系统设置](docs/screenshots/demo-settings.png) | > MongoDB → PostgreSQL 全量同步执行历史(754 条照片元数据,重跑多次幂等): > ![MongoDB→PG 全量同步执行历史](docs/screenshots/demo-mongodb-to-pg.png) ## 目录结构 ``` ├── backend/ # FastAPI 后端 │ ├── app/ │ │ ├── api/ # 路由(datasources/tasks/schedules/executions/cdc/files/notifications/users/dashboard/system) │ │ ├── services/ # 业务服务(含 datasource_adapters 适配器策略包、job_builder、table_service 等) │ │ ├── core/ # 公共能力(utils/identifier/db_factory/event_notifier/errors/security/timefmt) │ │ ├── models/ schemas/ │ │ ├── config.py database.py main.py │ │ └── requirements.txt │ ├── sql/full.sql # 元数据库权威全量 DDL(init.sql = \ir 兼容入口) │ └── tests/ # pytest 单元测试(默认门禁 853 passed / 0 skipped / 34 deselected) ├── frontend/ # Vue3 前端(views/ + components/task 子组件 + composables) ├── scripts/ # 一键启停(start-all / stop-all)+ #40 前端回归(ui_test/regression)+ dsp.py 五合一 CLI ├── dsp.bat # 研发工具链入口(scan / gate / test / release / up / down / status) ├── 一键启动.bat # 一键启动(仅后端 + 前端;不含 SeaTunnel) ├── 一键停止.bat # 一键停止 ├── docs/ # 全部文档(原 docs/in + docs/out 已归一,随仓库发布;32 份 .md) │ ├── screenshots/ # 界面截图(README 引用) │ └── code-feasibility-analysis/ # 可行性/分析类 HTML(分析稿一律放 docs/,见贡献指南 §5) └── LICENSE # Apache-2.0 ``` ## 文档导航 全部文档位于 `docs/`(已取消 in/out 内外分层),按用途索引如下: | 类别 | 文档 | 说明 | |------|------|------| | 使用 | [使用文档](docs/使用文档.md) | 功能操作指南与版本变更 | | 配置 | [前置配置指南](docs/前置配置指南.md) | 部署前环境 / 变量 / 元库 / 引擎配置 | | 配置 | [配置项参考](docs/配置项参考.md) | 全部环境变量与配置项清单 | | 运维 | [部署运维手册](docs/部署运维手册.md) | 生产部署、健康检查、安全加固 | | 运维 | [发版手册](docs/发版手册.md) | 发版流程与回滚 | | 测试 | [测试指南](docs/测试指南.md) | 测试体系、#40 前端自动化回归(221/0/5)与运行方式 | | 对接 | [接口文档 v0.2](docs/接口文档-v0.2.md) | REST API 契约 | | 协作 | [贡献指南与开发规范](docs/贡献指南与开发规范.md) | 分支 / 提交 / 高危操作铁律 / 文档放置规则(§5) | | 协作 | [研发全流程规范](docs/研发全流程规范.md) | 需求与缺陷 11 环节总纲(受理→复盘归档)、三级分级与门禁、模板 + 授权规则 | | 工具 | [dsp 工具使用手册](docs/dsp工具使用手册.md) | 研发工具链 CLI 单册参考:十子命令参数与输出判读(`check` 聚合打头)、五条场景流程、业界对照与改进候选、FAQ | | 规划 | [遗留任务排期](docs/遗留任务排期.md) | 版本规划与遗留项 | | 检索 | [已知缺陷索引](docs/已知缺陷索引.md) | 历史缺陷与已知限制的检索指针表(症状→根因→修复版本) | | 性能 | [性能报告](docs/性能报告.md) | T63 量化(v0.43~v0.52)+ 阶段五压测(附录 A 历史快照) | | 运维 | [历史发布与升级手册](docs/历史发布与升级手册.md) | 历史版本升级 runbook 存档 | | 方案 | [历史方案归档](docs/历史方案归档.md) | 已完成方案归并(T5/T40/T52/T56/T67) | > 全部文档(含技术方案 / 开发指南 / 故障排查 FAQ / 字段类型映射 / 达梦适配系列 / 数据库迁移指南 / 发版手册等)统一在 **`docs/` 目录并随仓库发布**(共 32 份 `.md`);完整清单见 [`docs/文档索引.md`](docs/文档索引.md)。 > **文档放置规则**:分析、设计方案、可行性报告等过程文档**一律写入 `docs/`**(多文件可用子目录),禁止落在仓库根目录——见 [贡献指南 §5](docs/贡献指南与开发规范.md)。 ## License [Apache License 2.0](LICENSE) © 2026 hwxus 本项目的执行引擎基于 [Apache SeaTunnel](https://seatunnel.apache.org)(Apache-2.0)二次开发。