From 1066d82c75e655597b7e470851e4acce23b87e4e Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 13 Aug 2026 04:39:57 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=20GVSite=20=E5=AD=90?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E6=8C=87=E9=92=88=E3=80=81TODO=20=E5=BE=85?= =?UTF-8?q?=E5=8A=9E=E6=B8=85=E5=8D=95=EF=BC=8C=E6=96=B0=E5=A2=9E=20GVSDSD?= =?UTF-8?q?K=20=E9=97=AE=E9=A2=98=E4=B8=8E=20SAGA=20=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GVSDSDK_IssueReport.md | 143 +++++++++++++++++++++++++++++++++++++++++ GVSite | 2 +- SAGA_Report.md | 134 ++++++++++++++++++++++++++++++++++++++ TODO | 5 +- 4 files changed, 281 insertions(+), 3 deletions(-) create mode 100644 GVSDSDK_IssueReport.md create mode 100644 SAGA_Report.md diff --git a/GVSDSDK_IssueReport.md b/GVSDSDK_IssueReport.md new file mode 100644 index 00000000..dc69b3b6 --- /dev/null +++ b/GVSDSDK_IssueReport.md @@ -0,0 +1,143 @@ +# GVSDSDK 问题报告 + +> 基于 `gvsdsdk` 包源码审查(2026-08-10),结合本会话代码阅读与项目既有文档(SAAS_ARCHITECTURE.md、项目记忆)。 +> 范围:`d:\SMANAGE\gvsdsdk`(约 15k 行 Python,55 个文件)。 +> 说明:问题按严重度分级,标注可定位位置与修复建议;部分问题为设计取舍,标注"既定决策"。 + +--- + +## 1. 问题总览 + +| # | 等级 | 分类 | 问题 | +|---|---|---|---| +| 1 | 高 | 事务 | `_call_service` 响应非 JSON 时事务卡死(Running 悬挂) | +| 2 | 高 | 事务 | 补偿失败后无重试补偿入口,事务只能人工兜底 | +| 3 | 高 | 架构 | 非托管模型与主库 schema 同步靠人工,migrations 冻结后漂移风险 | +| 4 | 中 | 架构 | User/Dept/Workgroup/Shop 无 TenantUUID,跨租户查询需 JOIN | +| 5 | 中 | 事务 | MaxRetries 无自动重试;RetryStep 无行锁 | +| 6 | 中 | 事务 | 无步骤间数据流(StepResult 不注入后续步骤) | +| 7 | 中 | 事务 | 超时以 CreateTime 起算,非空闲超时 | +| 8 | 中 | 权限 | ABAC 名实不符(本质是 RBAC 字符串集合) | +| 9 | 中 | 架构 | CompanyUUID 全链路冗余无 DB 约束,一致性靠应用层 | +| 10 | 中 | 工程 | 核心链路(Saga/分佣/支付/鉴权)零自动化测试 | +| 11 | 低 | 架构 | UserRole 遗留废弃字段 DeptUUID/WorkgroupUUID 仍在 schema | +| 12 | 低 | 事务 | TransactionResult 恒为空 | +| 13 | 低 | 事务 | 无幂等键,重复执行副作用靠业务自觉 | +| 14 | 低 | 工程 | 惰性加载 130+ 符号 → 无静态类型、IDE 跳转弱 | +| 15 | 低 | 工程 | 类型注解缺失(auth/managers.py 自认暂缓) | +| 16 | 低 | 文档 | SAAS_ARCHITECTURE.md 技术债描述与实际现状漂移 | + +--- + +## 2. 详细问题 + +### 2.1 高风险 + +#### #1 响应非 JSON 时事务卡死(Saga) +- **位置**:`gvsdsdk/msync/transaction.py` → `gvsds/apps/msync/transaction.py` `_call_service`(L538-566) +- **问题**:`resp.json()` 解析失败抛 JSONDecodeError,未被任何异常分支捕获;Execute 循环中断,事务永久停在 `Running`,不触发补偿,只能等 300s 超时兜底。 +- **建议**:捕获 `(ValueError, requests.RequestException)` 统一转 `StepExecutionError`,确保失败必进补偿链路。 + +#### #2 补偿失败无法重试补偿(Saga) +- **位置**:`gvsds/apps/msync/transaction.py` `Compensate`(L256-314) +- **问题**:补偿异常时步骤状态停留在 `Compensating`(非 Completed),再次 Compensate 的 completed_steps 查询不到该步骤 → 永远补不回来,事务 FAILED 待人工;无 re-compensate 接口。 +- **建议**:补偿失败步骤状态改 `Failed`,新增 `RetryCompensate` 入口(复用 RetryStep 骨架 + `select_for_update`)。 + +#### #3 非托管模型与主库 schema 同步靠人工 +- **位置**:`gvsdsdk/models.py`(全部模型 `managed=False`) +- **问题**:SDK 只映射不迁移,主库表结构由 gvsds 侧维护;migrations 冻结后(gvsdsdk/migrations 仅 1 个 `0001_drop_userdept`),字段新增/改名需人工双端同步,漏改一端即运行时静默漂移。 +- **证据**:gvsds 侧已无 `class Role/Permission/UserRole` 定义(gerp/models.py L778 从 gvsdsdk import,双份模型实际已收敛),收敛后 SDK 成为唯一模型源,但其结构约束力仅靠约定。 +- **建议**:建立 SDK 模型 ↔ 主库 schema 的一致性校验(如启动时 `_check_schema` 对照 db_table 字段清单),或恢复按 SDK 生成迁移。 + +### 2.2 中风险 + +#### #4 部分表无 TenantUUID +- **位置**:`gvsdsdk/models.py` User(L186)/ Department(L500)/ Workgroup(L1302)/ Shop(L831) +- **问题**:跨租户查询需经 Company→Tenant JOIN;租户删除/隔离审计困难(SAAS_ARCHITECTURE.md 6.2 已列)。 +- **建议**:向租户语义表补 `TenantUUID` 列并回填存量(迁移脚本),简化 `EnsureDefaultRoleForUser` 等处的租户解析链。 + +#### #5 MaxRetries 无自动重试;RetryStep 无行锁 +- **位置**:`gvsds/apps/msync/transaction.py` Execute(L211-244)/ RetryStep(L316-359) +- **问题**:正向流程失败直接补偿,`MaxRetries`/`CanRetry` 仅约束手动重试;RetryStep 无 `select_for_update`,并发重试竞态。 +- **建议**:Execute 内按 `CanRetry` 内联重试(可配置开关);RetryStep 加行锁。 + +#### #6 无步骤间数据流 +- **位置**:`gvsds/apps/msync/transaction.py` +- **问题**:`StepResult` 不注入后续步骤 payload;`TransactionPayload` 创建后不参与执行链。真实 Saga 的"A 输出 → B 输入"场景只能创建时预置全部数据。 +- **建议**:执行时将上一步 StepResult 合并进下一步 ActionPayload(向后兼容可选)。 + +#### #7 超时以 CreateTime 起算 +- **位置**:`gvsds/apps/msync/models.py` `IsTimedOut`(L232-239) +- **问题**:事务总预算 = 创建后 300s,非"最近活动空闲超时";多步骤慢事务易误伤,无活动推进重置机制。 +- **建议**:改为基于 `UpdateTime` 空闲判定,或事务级 heartbeat 推进。 + +#### #8 ABAC 名实不符 +- **位置**:`gvsdsdk/models.py` UserABAC(L798-810);`gvsdsdk/auth/permissions.py` +- **问题**:`HierarchicalPermissionIdentifiers` 为逗号分隔字符串集合,本质是简化 RBAC,无属性(时间/IP/资源所有者/字段级)判定能力;对外宣称 ABAC,扩展受限。 +- **建议**:短期文档更正为"属性标识符补充层";中期按策略表重构为真 ABAC。 + +#### #9 CompanyUUID 冗余无 DB 约束 +- **位置**:`gvsdsdk/models.py` UserRole/RolePermission/UserRoleDepartment/UserRoleWorkgroup/RoleShop +- **问题**:冗余隔离列无数据库级一致性约束,删公司/改归属时应用层漏写即脏数据;且各表隔离语义靠"约定一致"。 +- **建议**:至少对高频路径(UserRole/UserRoleDepartment)加索引与清理任务;长期考虑外键约束。 + +#### #10 核心链路零自动化测试 +- **位置**:`gvsdsdk` 无 tests 目录;`gvsds/tests` 仅 test_ip_filter/test_money/test_storage 三文件 +- **问题**:Saga 编排/补偿、分佣计算、支付网关、鉴权链路均无回归保障;本报告 #1/#2 类缺陷正是无测试的产物。 +- **建议**:优先补:Saga 状态机转换、补偿幂等、RoleManager 鉴权链路、金额计算四组单测。 + +### 2.3 低风险 + +#### #11 UserRole 遗留废弃字段 +- **位置**:`gvsdsdk/models.py` UserRole(L759-760) +- **问题**:DeptUUID/WorkgroupUUID 已废弃(注释禁止写入),但 schema 仍在,易被旧代码误写,语义歧义残留。 +- **建议**:迁移清理列,或至少全库扫描确认零写入后移除。 + +#### #12 TransactionResult 恒为空 +- **位置**:`gvsds/apps/msync/transaction.py` +- **问题**:模型字段存在,Execute/Compensate 从不写入,`GetDetail().Result` 恒 null。 +- **建议**:终态统一写入步骤汇总。 + +#### #13 无幂等键 +- **位置**:`gvsds/apps/msync/transaction.py` `_call_service` +- **问题**:无 Idempotency-Key;崩溃窗口内重复执行 action 的副作用靠业务补偿函数兜底。 +- **建议**:HTTP 头携带事务码+步骤号幂等键,工作服务侧去重(可选)。 + +#### #14 惰性加载无静态类型 +- **位置**:`gvsdsdk/__init__.py`(PEP 562 `__getattr__`,130+ 符号) +- **问题**:动态属性解析:IDE 跳转/补全弱、运行时属性访问有开销、`__all__` 未精确导出。 +- **建议**:保留惰性加载同时补充 `.pyi` 类型桩或精确 `__all__`。 + +#### #15 类型注解缺失 +- **位置**:`gvsdsdk/auth/managers.py`(L12 注释自认"类型注解暂缓") +- **问题**:~14k 行 Python 大面积无注解,与"双类导出"(自有实现/服务端转发)叠加后调用侧无类型保障。 +- **建议**:对公开 Manager 方法渐进补注解,优先 RoleManager/OrderManager。 + +#### #16 架构文档漂移 +- **位置**:`SAAS_ARCHITECTURE.md` 6.2 节 +- **问题**:仍记录"Role/Permission 模型双份定义未收敛",实际 gvsds 侧已改为 `from gvsdsdk.models import`(gerp/models.py L778),双份已收敛;文档未同步。 +- **建议**:更新技术债表,标注已收敛项,避免误导后续维护。 + +--- + +## 3. 优先级建议 + +| 优先级 | 动作 | 对应问题 | +|---|---|---| +| P0 | `_call_service` 异常兜底,失败必进补偿 | #1 | +| P0 | 补偿失败可重试(RetryCompensate + 行锁) | #2 | +| P1 | SDK 模型 ↔ 主库 schema 一致性校验 | #3 | +| P1 | Saga/鉴权/分佣/支付核心链路补单测 | #10 | +| P2 | 自动重试、步骤数据流、空闲超时、TransactionResult 写入 | #5/#6/#7/#12 | +| P2 | 补 TenantUUID、清理 UserRole 遗留列 | #4/#11 | +| P3 | 文档更正 ABAC 定位、更新架构文档、补类型桩 | #8/#14/#15/#16 | + +--- + +## 4. 结论 + +GVSDSDK 已从"薄封装"演进为通用 SAAS 服务层(P0/P1/P2 服务层化迁移完成),架构方向正确、收敛彻底;当前主要风险集中在**事务可靠性与工程保障**:2 项高风险缺陷(#1/#2)会直接造成线上事务悬挂或补偿不完整,建议优先修复;其次为模型层 schema 同步靠人工(#3)与核心链路零测试(#10)带来的长期回归风险。 + +--- + +*报告人:TraeCode(2026-08-10)* diff --git a/GVSite b/GVSite index 2c50a807..4c1cdb3c 160000 --- a/GVSite +++ b/GVSite @@ -1 +1 @@ -Subproject commit 2c50a8070b42f106e25d8ee542f3123bc912bb35 +Subproject commit 4c1cdb3c73f3c962aa22c2b51468c8e464fcdb64 diff --git a/SAGA_Report.md b/SAGA_Report.md new file mode 100644 index 00000000..ca163e1b --- /dev/null +++ b/SAGA_Report.md @@ -0,0 +1,134 @@ +# SAGA 分布式事务设计汇报 + +> 基于 `gvsdsdk/msync` + `gvsds/apps/msync` 源码分析(2026-08-10)。 +> 涉及文件:`gvsds/apps/msync/transaction.py`、`gvsds/apps/msync/models.py`、`gvsds/apps/msync/local_tx.py`、`gvsdsdk/msync/local_tx.py`、`gvsds/apps/msync/MSYNC.md`。 + +--- + +## 1. 架构定位:双包三层 + +``` +┌────────────────────────────── 主服务器(账本服务器)──────────────────────────────┐ +│ gvsds/apps/msync/transaction.py TransactionManager(Saga 编排引擎) │ +│ gvsds/apps/msync/models.py DistributedTransaction / TransactionStep │ +│ │ 正向: POST {domain}/api/msync/local/execute/ {StepName, payload} │ +│ │ 反向: POST {domain}/api/msync/local/compensate/ {StepName, payload, │ +│ │ ActionResult} │ +└────────┼───────────────────────────────┬─────────────────────────────────────────┘ + ▼ ▼ +┌────────────────────────┐ ┌────────────────────────┐ +│ gvsdsdk/msync/ │ │ gvsdsdk/msync/ │ +│ local_tx.py │ │ transaction.py │ +│ LocalTransactionManager│ │ 薄封装 → 转发 gvsds 原生层│ +│ (工作服务本地执行端) │ │ (仅主服务器可用) │ +└────────────────────────┘ └────────────────────────┘ +``` + +关键事实: + +- **编排端在主服务器,执行端在每个工作服务**,通过账本(`ServiceNode.ServiceDomain`)发现参与服务域名,HTTP 调用本地端点。 +- **SDK 薄封装**:`gvsdsdk/msync/transaction.py` 与 `ogm.py` 仅转发 gvsds 原生层,子服务器无 gvsds 依赖时抛 ImportError;`local_tx.py` 是**真实实现**,子服务器可直接注册步骤处理器。 +- **主服务器本身也当工作服务**:`gvsds/apps/msync/local_tx.py` 从 gvsdsdk 导入 `LocalTransactionManager`,主服务器同样可以参与 Saga 步骤。 +- 双包环形依赖:gvsdsdk(SDK)→ gvsds(主服务器)→ gvsdsdk(local_tx),靠惰性加载(PEP 562)避免初始化时序问题。 + +## 2. 状态机 + +### 事务 7 态(`DistributedTransaction`) + +``` +Pending(0) ──▶ Running(1) ──▶ Committed(2) (全部步骤成功) + │ + ├─▶ Failed(5) ──▶ Compensating(3) ──▶ Compensated(4) + │ + └─▶ TimedOut(6) ──▶ Compensating(3) ──▶ Compensated(4) +``` + +终态集合(`IsTerminal`)= Committed / Compensated / Failed / TimedOut。 + +### 步骤 7 态(`TransactionStep`) + +``` +Pending(0) ──▶ Running(1) ──▶ Completed(2) + │ + ├─▶ Compensating(3) ──▶ Compensated(4) + └─▶ Failed(5)(正向失败)/ Skipped(6)(事务取消跳过) +``` + +### 关键属性 + +- `IsTimedOut`:`CreateTime + TimeoutSeconds`(默认 300s)判定,已终态恒 False。 +- `CanRetry`:`RetryCount < MaxRetries`(默认 MaxRetries=3)。 + +## 3. 核心流程 + +### 3.1 正向执行(`Execute`) + +1. `select_for_update()` 锁行(防并发推进同一事务)。 +2. 校验状态 ∈ {Pending, Running};超时则标记 TimedOut 并 `on_commit` 补偿。 +3. 置 Running → 按 `StepIndex` 逐步骤执行: + - 已 Completed 步骤跳过(断点续跑语义); + - `_execute_step`:标记步骤 Running → POST 参与服务 execute 端点 → 返回结果 → 标记 Completed + 保存 StepResult; + - 任一失败:步骤标记 Failed,记录错误快照,`on_commit` 触发 `Compensate`。 +4. 全部完成 → 事务 Committed。 + +### 3.2 反向补偿(`Compensate`) + +1. `select_for_update()` 锁行;已 Compensated 直接返回(幂等)。 +2. 事务置 Compensating → **逆序**遍历 `StepStatus=Completed` 的步骤。 +3. 每步 `_compensate_step`:把该步骤原始 `StepResult` 作为 `ActionResult` 随请求传回 → 业务补偿函数可据此幂等回滚。 +4. 补偿成功 → 步骤 Compensated;补偿失败 → 记录 `compensate_error`(**步骤状态停留在 Compensating**)。 +5. 若存在仍在 Compensating 的步骤 → 事务 Failed;否则 Compensated。 + +### 3.3 超时与兜底 + +- 双保险:执行中逐步骤检测 `IsTimedOut`(`on_commit` 补偿)+ `CheckTimeouts()` 轮询兜底(需 Celery 定时任务触发)。 + +### 3.4 重试 + +- **手动重试**:`RetryStep(transaction_code, step_index)` 仅允许 Failed/Pending 步骤,校验 `CanRetry`,重跑 action。 +- **注意**:Execute 正向流程中**没有自动重试**逻辑——步骤失败直接进入补偿,`MaxRetries` 仅约束手动重试次数。 + +## 4. 传输层设计 + +| 项 | 配置 | +|---|---| +| 会话 | 模块级 `requests.Session`,连接池 10 | +| TLS | 显式 `verify=True`,支持 `REQUESTS_CA_BUNDLE` 环境变量自定义 CA | +| 重试 | 502/503/504 自动重试 3 次,backoff 0.5s,仅 POST | +| 超时 | 单次请求 30s | +| 鉴权 | `Authorization: Service `(HMAC 验权签发,2h 有效) | +| 响应契约 | 兼容 `{code:200, data}`(DRF)与 `{success, result, error}`(本地管理器) | + +## 5. 设计亮点 + +1. **远程编排 + 本地执行彻底解耦**:子服务器仅依赖 SDK `local_tx` 注册处理器即可接入,无需理解编排。 +2. **补偿带回 ActionResult**:补偿函数拿到原始执行结果,可精确、幂等地回滚(如按返回的 user_uuid 删除)。 +3. **行锁防并发**:Execute / Compensate 均 `select_for_update`。 +4. **on_commit 补偿**:补偿在主事务提交后触发,避免"正向已回滚却补偿"的错乱。 +5. **断点续跑**:Execute 跳过已完成步骤,支持中途失败后整体重跑推进。 +6. **协议双兼容**:`_call_service` 同时解析两套响应契约。 + +## 6. 缺陷与风险 + +| 等级 | 问题 | 位置 | 说明 | +|---|---|---|---| +| 高 | 响应非 JSON 时事务卡死 | `_call_service`(transaction.py L538-566) | `resp.json()` 解析失败抛 JSONDecodeError 未捕获 → Execute 中断 → 事务永久停 Running,不触发补偿,需等 300s 超时 | +| 高 | 补偿失败后无法重试补偿 | `Compensate`(L256-314) | 补偿异常时步骤状态停在 Compensating(非 Completed),再次 Compensate 查不到它 → 永远补不回来,事务 Failed 只能人工处理,无 re-compensate 入口 | +| 中 | MaxRetries 无自动重试 | `Execute`(L211-244) | 失败直接补偿,`CanRetry` 只在手动 RetryStep 生效;RetryStep 无 `select_for_update`,并发重试有竞态 | +| 中 | 无步骤间数据流 | `Execute`/`_execute_step` | `StepResult` 不注入后续步骤 payload;TransactionPayload 创建后不参与执行。无法表达"A 步骤输出是 B 步骤输入"的链式场景 | +| 中 | 超时以 CreateTime 起算 | `models.py IsTimedOut` | 非"最近活动空闲超时",10 步慢事务总预算仅 300s,无活动推进重置机制 | +| 低 | TransactionResult 恒空 | `Execute`/`Compensate` | 模型有字段但从不写入,`GetDetail().Result` 永远 null | +| 低 | 幂等依赖业务自觉 | `_call_service` | 无全局幂等键,崩溃窗口内重复执行 action 的副作用靠业务方补偿兜底 | + +## 7. 改进建议(按优先级) + +1. `_call_service` 捕获 JSON 解析/异常 → 统一转 `StepExecutionError`,保证失败必进补偿链路。 +2. 补偿失败步骤状态改为 Failed 并提供 `RetryCompensate` 入口(复用 RetryStep 骨架 + 行锁)。 +3. `RetryStep` 补 `select_for_update`;若需自动重试,在 Execute 循环内按 `CanRetry` 内联重试。 +4. 支持步骤结果注入下一步 ActionPayload(可选项,向后兼容)。 +5. 超时改为基于 `UpdateTime` 的空闲判定或提供事务级 heartbeat。 +6. Execute/Compensate 末尾统一写入 `TransactionResult` 汇总。 + +--- + +*汇报人:TraeCode(2026-08-10)* diff --git a/TODO b/TODO index f0f60374..c55a1552 100644 --- a/TODO +++ b/TODO @@ -1,2 +1,3 @@ -成员邮箱和 gitea 与 gerp 同步 - +# 成员邮箱和 gitea 与 gerp 同步 +像阿里云一样的百科,解释 GERP 的各个机制 +一套配色系统(主题色和配色方案)