批次4后续专项完成:D11清偿 + OCC方案B实施 + 部署参数 + D2诚实标注 + CI门禁
① D11 HTML 报告 RustFS 单源化(TECH_DEBT P2 清偿):可视化产物写任务临时目录后
裸传报告键 html/reports/{filename}(文件名寻址),/html StaticFiles 挂载删除,
新增 html_report_router 根路径代理(报告键→遗留 JSON 包装→本地卷兜底→404,
防穿越);URL 形状 /html/{filename} 不变,持久化引用零迁移;celery 摘除
html_data 卷,镜像不再烤入陈旧报告;顺带删除 get_stp_file_with_data 死数据块
② OCC 方案 B(D10 清偿):run_occ(op_name, payload) 契约 + 常驻工作进程池
(occ_process_pool + occ_worker 操作注册表),超时/崩溃 terminate 换新补位、
任务级超时 recover 整体重建,残留线程泄漏根治;TopoDS 不跨进程(generate_cavity
分模 + 方案 STEP 持久化全在子进程内,返回 export_manifest);删除内存形状缓存链、
CADExporter.export_mold_results、shape_loader(→ stp_materializer)
③ OCC 方案 A 部署参数:CELERY_CONCURRENCY / CELERY_MAX_TASKS_PER_CHILD 进
Dockerfile.celery + compose + .env.example
④ D2 诚实标注:铝价响应带 source: "simulated",前端按来源渲染标注(原硬编码
"上海期货交易所"属虚假声明),死代码 getAluminumPrice 删除
⑤ CI 门禁:.gitea/workflows/ci.yml 三 job(pytest / 前端构建含 vue-tsc /
openapi 漂移检测)
接口变更三件套随批完成(openapi 76→77 paths + gen:api + 前端构建通过;方案 B
接口面零变化)。测试基线 143 passed, 0 skipped(新增 16 项)。文档六处同步。
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
批次 3 自 storage_integration_rustfs.py 按职责拆分(见 task_storage_service.py 头注)。
|
||||
"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
from sqlalchemy import select
|
||||
@@ -270,39 +271,29 @@ class AnalysisStorageService:
|
||||
stp_file_id: int,
|
||||
filename: str,
|
||||
file_path: str,
|
||||
html_content: Optional[str] = None,
|
||||
visualization_type: str = "3d_viewer") -> HTMLFile:
|
||||
"""保存HTML文件到PostgreSQL元数据 + RustFS对象存储"""
|
||||
"""保存HTML文件:正文按报告键裸传 RustFS + PG 仅存元数据(D11)。
|
||||
|
||||
# 1. 获取文件哈希
|
||||
stp_file = await session.get(STPFile, stp_file_id)
|
||||
file_hash = stp_file.file_hash
|
||||
上传键固定 html/reports/{filename}(文件名寻址),读侧 GET /html/{filename}
|
||||
按文件名直取,不再写 JSON 包装对象(遗留 html/{hash}.json 仅由读侧兼容解析)。
|
||||
file_path 为任务内临时目录路径,任务结束即删除,仅供追溯,不作为读取来源。
|
||||
"""
|
||||
html_file_path = Path(file_path)
|
||||
if not html_file_path.exists():
|
||||
raise RuntimeError(f"HTML 可视化文件缺失: {file_path}")
|
||||
html_bytes = html_file_path.read_bytes()
|
||||
|
||||
# 2. 读取HTML内容(如果未提供)
|
||||
if html_content is None:
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
html_content = f.read()
|
||||
except Exception as e:
|
||||
logger.error(f"读取HTML文件失败: {e}")
|
||||
html_content = ""
|
||||
|
||||
# 3. 上传到RustFS
|
||||
html_json = {'content': html_content, 'filename': filename}
|
||||
upload_result = await rustfs_manager.upload_json_data(
|
||||
file_type='html_files',
|
||||
json_data=html_json,
|
||||
file_hash=file_hash
|
||||
object_key = await rustfs_manager.upload_report_artifact(
|
||||
filename, html_bytes, content_type="text/html; charset=utf-8"
|
||||
)
|
||||
|
||||
# 4. 创建PostgreSQL记录
|
||||
html_file = HTMLFile(
|
||||
stp_file_id=stp_file_id,
|
||||
object_key=upload_result['object_key'],
|
||||
storage_bucket=upload_result['bucket'],
|
||||
object_key=object_key,
|
||||
storage_bucket=rustfs_manager.bucket_name,
|
||||
filename=filename,
|
||||
file_path=file_path, # 保留本地路径
|
||||
# 停止双写完整 HTML 进 PG:读取路径走 RustFS(html_json.content),
|
||||
file_path=file_path,
|
||||
# 停止双写完整 HTML 进 PG:读取路径走 /html/{filename} 代理,
|
||||
# PG 仅存对象键与文件名,避免大文本撑爆表
|
||||
html_content=None,
|
||||
visualization_type=visualization_type
|
||||
@@ -313,7 +304,7 @@ class AnalysisStorageService:
|
||||
await session.flush()
|
||||
await session.refresh(html_file)
|
||||
|
||||
logger.info(f"HTML文件保存成功 RustFS: {html_file.id}")
|
||||
logger.info(f"HTML文件保存成功 RustFS: {html_file.id} ({object_key})")
|
||||
return html_file
|
||||
|
||||
async def save_features_and_recommendations(
|
||||
@@ -386,7 +377,6 @@ class AnalysisStorageService:
|
||||
'geometry_data': None,
|
||||
'mesh_data': None,
|
||||
'mold_cavity_data': None,
|
||||
'html_content': None,
|
||||
'features': [],
|
||||
'recommendations': [],
|
||||
'analysis_metrics': None # 新增分析指标字段
|
||||
@@ -418,14 +408,10 @@ class AnalysisStorageService:
|
||||
)
|
||||
result['mesh_data'] = json.loads(mesh_bytes.decode('utf-8'))
|
||||
|
||||
# HTML文件
|
||||
if stp_file.html_file:
|
||||
html_bytes = await rustfs_manager.download_file(
|
||||
file_type='html_files',
|
||||
object_key=stp_file.html_file.object_key
|
||||
)
|
||||
html_json = json.loads(html_bytes.decode('utf-8'))
|
||||
result['html_content'] = html_json.get('content', '')
|
||||
# HTML 正文不再随本视图下载(D11):历史实现把整个 HTML 读进
|
||||
# result['html_content'],但所有调用方只取 geometry/cavity/features,
|
||||
# HTML 的读取入口是 /html/{filename} 代理路由——每次任务查询白下载
|
||||
# 数 MB 正文纯属浪费,已删除
|
||||
except Exception as e:
|
||||
logger.error(f"从RustFS获取数据失败: {e}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user