优化
This commit is contained in:
+56
-74
@@ -25,6 +25,8 @@
|
||||
- debug/history 路由补鉴权
|
||||
- 任务访问控制收紧
|
||||
- 无主数据不再默认放行
|
||||
- `/api/status/{task_id}` 补 JWT 鉴权与归属校验(原 D5,2026-09-16 清偿,见 D5 条目)
|
||||
- bcrypt 创建口令超 72 字节显式拒绝、验证侧截断比较;`SECRET_KEY` / `RUSTFS_*` 缺失时明确报错,代码侧弱默认移除(D14 部分,2026-09-16)
|
||||
|
||||
### 2.2 静默失败与可用性
|
||||
- `detect-undercuts` 改为基于真实 shape 分析
|
||||
@@ -41,6 +43,18 @@
|
||||
- 设置惰性配置校验,提升可测试性
|
||||
- Generator 公共接口提取完成,补充契约测试
|
||||
|
||||
### 2.5 部署正确性(2026-09-16,批次 0/1)
|
||||
- `/api/status/{task_id}` 补鉴权与归属校验(原 D5)
|
||||
- 主处理链路改走 RustFS:分派入参 `stp_file_id` 化,源文件按 object_key 下载;compose 共享卷过渡兜底(原 D6)
|
||||
- `AUTO_MIGRATE` 开关 + 迁移脚本随镜像分发 + `alembic/`→`migrations/` 改名修复包遮蔽(原 D12)
|
||||
- OCC 镜像改 conda 运行时原生执行、基础镜像 tag 锁定(D13 主体);compose 关键项去弱默认(D14 部分)
|
||||
|
||||
### 2.6 任务一致性模型(2026-09-16,批次 2)
|
||||
- Redis 内存回退彻底删除,PG 为任务状态单一事实源(原 D7);批量元数据入库(`processing_tasks.batch_id`,迁移 `a3f8c2d91e47`)
|
||||
- 型腔生成失败任务标 failed,不再静默 completed(原 D8)
|
||||
- 持久化事务边界收口:数据本体分阶段原子提交、失败先回滚再置 failed(原 D9)
|
||||
- D11(HTML 双写双读)本批未动:正确性已由共享卷兜底,RustFS 单一来源留待后续批次
|
||||
|
||||
详细历史过程保留在原始技术债文档中,后续将转入归档。
|
||||
|
||||
---
|
||||
@@ -111,74 +125,51 @@
|
||||
|
||||
优先级:**P1**
|
||||
|
||||
### D5. `/api/status/{task_id}` 未鉴权(安全缺口)
|
||||
### D5. `/api/status/{task_id}` 未鉴权(安全缺口)—— 已清偿(2026-09-16,批次 0)
|
||||
|
||||
现状:
|
||||
- [src/moldinsight/api/task_router.py](../src/moldinsight/api/task_router.py) 的 `/api/status/{task_id}` 未挂 `get_current_active_user`,也无任务归属校验
|
||||
- 匿名可枚举任务号拉取完整分析视图(几何 / 型腔方案 / LLM 报告 / 服务器本地路径)
|
||||
修复内容(保留编号以维持 D6–D14 引用稳定):
|
||||
- 端点补 `Depends(get_current_active_user)`;归属校验收敛为 `TaskQueryService.ensure_task_access`,task_router 与 advanced_router 共用(advanced_router 原私有 `_ensure_task_access` 改为委托)
|
||||
- 语义:无 token 401、他人/无主任务 403(无主不等于公共)、任务不存在 404
|
||||
- 回归测试:[tests/test_status_endpoint_auth.py](../tests/test_status_endpoint_auth.py)
|
||||
- 接口行为变化已同步 [API_CONTRACT.md](API_CONTRACT.md) §3.2
|
||||
|
||||
影响:
|
||||
- 与"任务访问控制已收紧"的既有结论矛盾;任务号可经批量/历史接口关联到真实用户
|
||||
- 属确认的安全漏洞,应最先修复
|
||||
~~原现状 / 影响~~:端点未挂鉴权,匿名可枚举任务号拉取完整分析视图。
|
||||
|
||||
建议:
|
||||
- 补 `Depends(get_current_active_user)` 并复用 `_ensure_task_access` 归属校验
|
||||
### D6. 主处理链路依赖节点本地文件路径 —— 已清偿(2026-09-16,批次 1)
|
||||
|
||||
优先级:**P0**
|
||||
修复内容(保留编号以维持引用稳定):
|
||||
- 分派入参收敛为 `stp_file_id`(`dispatch_processing` 与 Celery 任务签名同步变更):处理方按 PG 元数据从 RustFS 下载源文件到任务专属临时目录(保留原始文件名,下游产物命名不变),任务结束即清理([processing_service.py](../src/moldinsight/services/processing_service.py) `_materialize_source_file`)
|
||||
- RustFS 不可用时回退 `STPFile.file_path` 节点本地路径;compose 为 backend / celery 增加共享卷 `uploads_data` / `html_data` 作过渡兜底(HTML 产物跨容器写读同源问题一并兜住,正式修复在 D11)
|
||||
|
||||
### D6. 主处理链路依赖节点本地文件路径
|
||||
~~原现状 / 影响~~:worker 直读 API 节点本地路径,双容器部署必然 `FileNotFoundError`。
|
||||
|
||||
现状:
|
||||
- 上传保存到本地目录,任务处理直接 `load_step_file(Path(file_path))`([processing_service.py](../src/moldinsight/services/processing_service.py))
|
||||
- docker-compose 中 backend 与 moldinsight-celery 为独立容器且无共享 volume,worker 读不到 API 节点写入的本地文件
|
||||
### D7. Redis 降级为进程内 dict,多副本状态不一致 —— 已清偿(2026-09-16,批次 2)
|
||||
|
||||
影响:
|
||||
- 双容器部署下主流程必然 `FileNotFoundError`;代码已有从 RustFS 重建几何的 [shape_loader.py](../src/moldinsight/services/shape_loader.py),主链路却未复用
|
||||
修复内容(比原建议更彻底:完全删除内存回退,而非仅限 DEBUG):
|
||||
- [redis_task_manager.py](../src/shared/services/redis_task_manager.py) 删除全部 `_fallback_*` 进程内存存储:Redis 不可用时写 no-op、读返回 None(Redis 仅热缓存,任务状态事实源在 PG,缓存缺失不影响正确性)
|
||||
- 批量元数据入库:`processing_tasks` 新增 `batch_id` 列(迁移 `a3f8c2d91e47`),`GET /api/batch/{batch_id}` 改为按列聚合查询 + `STPFile.user_id` 归属校验,删除 Redis batch key 与进程内 dict 双通道
|
||||
- `TaskQueryService` 的 PG 组装视图补 `progress` / `current_step`(Redis 不可用时前端轮询仍能看到进度);batch 聚合响应同步补 `current_step`
|
||||
|
||||
建议:
|
||||
- 分派入参由 `file_path` 改为 `stp_file_id`,worker 端按 `object_key` 从 RustFS 下载后解析
|
||||
~~原现状 / 影响~~:Redis 故障时状态静默降级各进程内存,多副本互不可见、同任务不同副本读到不同状态。
|
||||
|
||||
优先级:**P0**
|
||||
### D8. 型腔生成失败被静默标记为 completed —— 已清偿(2026-09-16,批次 2)
|
||||
|
||||
### D7. Redis 降级为进程内 dict,多副本状态不一致
|
||||
修复内容:
|
||||
- [processing_service.py](../src/moldinsight/services/processing_service.py) `_step_generate_cavity` 不再吞异常:分模失败直接向编排层传播 → 任务 failed(error_message 说明型腔阶段失败);已提交的几何/网格数据保留,用户可凭失败原因重新分析
|
||||
- 未采用 `completed_with_fallback`:多一个状态值会扩散到前端所有状态分支,failed + 明确错误更诚实且成本低
|
||||
|
||||
现状:
|
||||
- Redis 不可用时任务状态 / 批量元数据 / 任务视图缓存静默降级到各进程内存([redis_task_manager.py](../src/shared/services/redis_task_manager.py) / [batch_router.py](../src/moldinsight/api/batch_router.py) / [task_query_service.py](../src/moldinsight/services/task_query_service.py))
|
||||
~~原现状 / 影响~~:型腔失败被吞掉继续主流程,最终 completed,"完成"状态不可信。
|
||||
|
||||
影响:
|
||||
- 多 worker + 多 API 副本下各进程内存互相不可见:同一任务在不同副本读到不同状态
|
||||
### D9. 持久化事务边界破碎 —— 已清偿(2026-09-16,批次 2)
|
||||
|
||||
建议:
|
||||
- PG 作为单一事实源、Redis 仅热缓存;内存回退仅限单进程 DEBUG 模式
|
||||
修复内容(进度可见性与原子性折中设计):
|
||||
- **数据本体写方法只 flush 不 commit**:`save_stp_file` / `save_geometry_data` / `save_mesh_data` / `save_mold_cavity_data` / `save_html_file` / `save_features_and_recommendations` / `update_task_parameters` / `update_stp_file_analysis_summary` / `_save_analysis_metrics` / `_save_verification_metrics`
|
||||
- **编排层分阶段收口**([processing_service.py](../src/moldinsight/services/processing_service.py)):阶段 A = 几何+网格(解析后确定成果,原子提交);阶段 B = 型腔+HTML+特征+指标+摘要+验证(结果包原子提交);完成时先 flush 任务参数、完成状态提交时一并落库(completed 即完整)
|
||||
- **失败路径先 rollback 再置 failed**:未提交半成品回滚,失败状态单独提交,不出现"completed 但数据残缺"
|
||||
- **保留即时 commit**:`update_task_status` / `update_stp_file_status`(处理中进度需跨事务对外可见,分钟级长任务不能憋在一个大事务里)
|
||||
- 调用方补显式 commit:upload_router / batch_router(分派前置事务,STPFile + ProcessingTask 原子,消除孤儿文件记录)、advanced_router 导出两处
|
||||
|
||||
优先级:**P1**
|
||||
|
||||
### D8. 型腔生成失败被静默标记为 completed
|
||||
|
||||
现状:
|
||||
- `_step_generate_cavity` 异常时置 `plan_result=None` 继续主流程,最终任务标记 completed([processing_service.py](../src/moldinsight/services/processing_service.py))
|
||||
|
||||
影响:
|
||||
- 核心能力失败却对外呈现"成功","完成"状态可信度低
|
||||
|
||||
建议:
|
||||
- 型腔失败 → 任务 failed,或显式 `completed_with_fallback` 并前端标注
|
||||
|
||||
优先级:**P1**
|
||||
|
||||
### D9. 持久化事务边界破碎
|
||||
|
||||
现状:
|
||||
- [storage_integration_rustfs.py](../src/moldinsight/services/storage_integration_rustfs.py) 各方法内部自行 `session.commit()`,编排层上下文又 commit
|
||||
- 型腔保存失败时几何/网格等前期数据已提交落库
|
||||
|
||||
影响:
|
||||
- 失败后留下已提交的半成品数据,无对账补偿
|
||||
|
||||
建议:
|
||||
- 各方法不再自提交,由编排层统一提交;明确 RustFS 与 PG 写入顺序
|
||||
|
||||
优先级:**P1**
|
||||
~~原现状 / 影响~~:各存储方法内部自行 commit,型腔保存失败留半成品数据且任务仍 completed。
|
||||
|
||||
### D10. OCC 全局单线程串行 + 超时重建泄漏线程
|
||||
|
||||
@@ -209,35 +200,26 @@
|
||||
|
||||
### D12. 应用启动时自动执行 alembic 迁移
|
||||
|
||||
现状:
|
||||
- [init_db.py](../src/shared/database/init_db.py) 在 web 进程 startup 中执行 `alembic upgrade head`
|
||||
### D12. 应用启动时自动执行 alembic 迁移 —— 已清偿(2026-09-16,批次 1)
|
||||
|
||||
影响:
|
||||
- 多副本并发迁移有竞态,且迁移阻塞服务就绪
|
||||
修复内容:
|
||||
- 新增 `AUTO_MIGRATE` 开关(settings / .env.example / compose 透传):默认 `true` 保持单机开发行为;多副本部署设 `false`,由部署流程单点执行 alembic CLI 或 `python -m shared.database.init_db`
|
||||
- **连带发现并修复两个使自动迁移从未真正生效的缺陷**:
|
||||
1. 迁移目录 `alembic/` 与 alembic 包重名——应用内 `import alembic` 命中本地目录(namespace package)遮蔽真实包,启动期迁移异常被 `init_database` 吞掉只打日志;已改名 `migrations/`(alembic.ini `script_location` 与 4 处文档引用同步)
|
||||
2. 镜像未打包迁移脚本与 alembic.ini,容器内迁移必然失败——Dockerfile.base / Dockerfile.moldinsight 已补 `COPY migrations/` + `COPY alembic.ini`
|
||||
|
||||
建议:
|
||||
- 迁移移出 web 进程,作为独立部署步骤(`AUTO_MIGRATE` 开关)
|
||||
|
||||
优先级:**P1**
|
||||
|
||||
### D13. PythonOCC 镜像引入方式脆弱 + 依赖无版本锁
|
||||
### D13. PythonOCC 镜像引入方式脆弱 + 依赖无版本锁(主体已清偿,锁文件遗留)
|
||||
|
||||
现状:
|
||||
- [Dockerfile.moldinsight](../deploy/Dockerfile.moldinsight) 从 conda env 拷贝 site-packages 进 python:3.12-slim
|
||||
- [requirements.txt](../requirements.txt) 全部为 `>=` 下限,无锁文件
|
||||
- ~~从 conda env 拷贝 site-packages 进 python:3.12-slim~~(2026-09-16 已修正:[Dockerfile.moldinsight](../deploy/Dockerfile.moldinsight) 改为 conda 运行时原生执行,不再跨镜像拷贝;基础镜像 tag 锁定 `continuumio/miniconda3:24.7.1-0`、`python:3.12-slim-bookworm`;tag 可用性随下次镜像构建验证)
|
||||
- [requirements.txt](../requirements.txt) 全部为 `>=` 下限,无锁文件(**遗留**:首次镜像构建成功后 `pip freeze` 生成锁文件,命令已注释在 Dockerfile 内)
|
||||
|
||||
影响:
|
||||
- slim 缺 libstdc++/libgomp 等运行时库,跨发行版拷二进制纯靠运气;构建不可复现
|
||||
|
||||
建议:
|
||||
- 基础镜像改用完整 conda 环境;依赖以 pip-compile 锁文件固化
|
||||
|
||||
优先级:**P2**
|
||||
优先级:**P2**(剩余锁文件部分)
|
||||
|
||||
### D14. 配置漂移:弱默认 / 死配置 / 重复解析
|
||||
|
||||
现状:
|
||||
- RUSTFS_* 带 `localhost:8080` / `your-secret-key` 弱默认;compose 给 SECRET_KEY / ADMIN_PASSWORD 弱默认
|
||||
- ~~RUSTFS_* 弱默认~~(2026-09-16 代码侧已去除);~~compose 侧 SECRET_KEY / ADMIN_PASSWORD 弱默认~~(2026-09-16 已去除:改用 `${VAR:?}` 强制显式配置,`create_admin_user` 对空 ADMIN_PASSWORD 显式报错)
|
||||
- MAX_FILE_SIZE 配置项未被使用([file_handler.py](../src/shared/utils/file_handler.py) 硬编码 50MB)
|
||||
- [celery_app.py](../src/celery_app.py) 重新 load_dotenv 并手拼 REDIS URL,与 settings 两份实现
|
||||
|
||||
|
||||
Reference in New Issue
Block a user