VWED_server/docs/task_log_hierarchy_upgrade.md

284 lines
7.6 KiB
Markdown

# 任务日志层级关系优化方案
## 改造背景
### 原有问题
1. **日志表缺少层级关系字段**: `vwed_tasklog` 表只有基本字段,没有记录父子关系、迭代索引等信息
2. **层级重构困难**: `get_block_results` 接口需要解析日志中的 JSON `output.iterationResults` 来重构层级,不稳定
3. **循环日志分散**: 循环块的日志("第1次循环")和子块执行日志是分开的,前端难以组织嵌套显示
### 期望效果
对于循环任务,期望返回的数据结构为:
```json
{
"children": [
{
"iterationIndex": 0,
"success": true,
"iterationLogs": [
{"message": "第1次循环, item=1"}
],
"children": [
{
"blockName": "b4",
"blockType": "PrintBp",
"logs": [
{"message": "打印: 0"}
]
}
]
}
]
}
```
## 改造方案
### 1. 数据库表结构扩展
#### 新增字段
`vwed_tasklog` 表添加以下字段:
| 字段名 | 类型 | 说明 |
|-------|------|------|
| `parent_log_id` | VARCHAR(255) | 父日志ID,用于建立层级关系 |
| `iteration_index` | INT | 迭代索引,记录是第几次循环(从0开始) |
| `block_record_id` | VARCHAR(255) | 关联的块执行记录ID |
| `log_type` | VARCHAR(50) | 日志类型: `iteration_start`, `iteration_end`, `block_execution`, `branch_execution` |
#### 迁移脚本
位置: `migrations/versions/004_add_tasklog_hierarchy_fields.py`
执行迁移:
```bash
cd /mnt/d/jsw_code/project/VWED_server
alembic upgrade head
```
### 2. 日志记录逻辑改造
#### TaskContext 扩展
`services/execution/task_context.py` 中添加:
```python
self.parent_log_id = None # 当前父日志ID
self.current_iteration_index = None # 当前迭代索引
def set_iteration_context(self, parent_log_id: str = None, iteration_index: int = None):
"""设置当前迭代上下文"""
self.parent_log_id = parent_log_id
self.current_iteration_index = iteration_index
```
#### BlockHandler 日志记录方法
修改 `services/execution/handlers/base.py``_record_task_log` 方法:
```python
async def _record_task_log(
self,
block: Dict[str, Any],
result: Dict[str, Any],
context: Any,
log_type: str = "block_execution",
parent_log_id: str = None,
iteration_index: int = None
) -> str:
"""记录任务日志,返回日志ID"""
# ... 记录时包含 parent_log_id, iteration_index, log_type 等字段
```
#### IterateListBlockHandler 改造
`services/execution/handlers/progress.py` 的迭代处理逻辑中:
```python
for index, item in enumerate(array_data):
# 1. 记录迭代开始日志,作为该次迭代的父日志
iteration_start_log_id = await self._record_task_log(
block,
{"success": True, "message": f"第{index+1}次循环, item={item}"},
context,
log_type="iteration_start",
iteration_index=index
)
# 2. 设置迭代上下文,后续子块日志都会关联到这个父日志
context.set_iteration_context(parent_log_id=iteration_start_log_id, iteration_index=index)
# 3. 执行循环体(子块日志会自动记录parent_log_id和iteration_index)
loop_result = await executor.execute_children(block, "default")
# 4. 清除迭代上下文
context.clear_iteration_context()
```
### 3. 查询接口优化
#### 新版 get_block_results_v2
创建新文件 `services/task_record_service_new.py`,实现基于层级关系字段的查询逻辑:
**核心思路**:
1. **构建映射表**:
- `log_map_by_block`: 按块名称分组日志
- `log_map_by_parent`: 按父日志ID分组子日志
2. **识别迭代块**:
- 检查 `block_type` 是否为 `ITERATE_LIST`, `WHILE`, `REPEAT_NUM`
- 找出所有 `log_type="iteration_start"` 的日志
3. **按迭代组织**:
```python
for iter_log in iteration_start_logs:
iteration_item = {
"iterationIndex": iter_log.iteration_index,
"iterationLogs": [iter_log], # 迭代开始日志
"children": [] # 该次迭代的子块
}
# 查找 parent_log_id = iter_log.id 的所有子日志
child_logs = log_map_by_parent.get(iter_log.id, [])
# ... 递归构建子块
```
4. **递归处理嵌套**:
- 如果子块也是迭代块,继续应用相同逻辑
- 普通块直接递归处理其子块
#### 兼容旧版本
在 `services/task_record_service.py` 中:
```python
@staticmethod
async def get_block_results(task_record_id: str, use_new_version: bool = True):
if use_new_version:
from services.task_record_service_new import get_block_results_v2
return await get_block_results_v2(task_record_id)
# ... 旧版本逻辑(基于JSON解析)
```
## 数据流示例
### 任务定义
```json
{
"rootBlock": {
"id": -1,
"name": "-1",
"blockType": "RootBp",
"children": {
"default": [
{
"id": 5,
"name": "b3",
"blockType": "IterateListBp",
"inputParams": {
"list": {"value": "[1, 2, 3]"}
},
"children": {
"default": [
{
"id": 6,
"name": "b4",
"blockType": "PrintBp",
"inputParams": {
"message": {"value": "blocks.b3.index"}
}
}
]
}
}
]
}
}
}
```
### 日志记录流程
| 时间 | 操作 | 日志记录 |
|------|------|---------|
| T1 | 开始第1次循环 | `log_id=L1, task_block_id=b3, log_type=iteration_start, iteration_index=0, parent_log_id=null` |
| T2 | 执行打印块 | `log_id=L2, task_block_id=b4, log_type=block_execution, iteration_index=0, parent_log_id=L1` |
| T3 | 开始第2次循环 | `log_id=L3, task_block_id=b3, log_type=iteration_start, iteration_index=1, parent_log_id=null` |
| T4 | 执行打印块 | `log_id=L4, task_block_id=b4, log_type=block_execution, iteration_index=1, parent_log_id=L3` |
### 查询结果组织
```json
{
"blockName": "b3",
"blockType": "IterateListBp",
"children": [
{
"iterationIndex": 0,
"iterationLogs": [
{"logId": "L1", "message": "第1次循环, item=1"}
],
"children": [
{
"blockName": "b4",
"logs": [
{"logId": "L2", "message": "打印: 0", "parent_log_id": "L1"}
]
}
]
},
{
"iterationIndex": 1,
"iterationLogs": [
{"logId": "L3", "message": "第2次循环, item=2"}
],
"children": [
{
"blockName": "b4",
"logs": [
{"logId": "L4", "message": "打印: 1", "parent_log_id": "L3"}
]
}
]
}
]
}
```
## 优势
1. **数据完整性**: 日志记录时就建立层级关系,不依赖运行时的内存状态
2. **查询性能**: 通过索引直接查询层级关系,无需解析JSON
3. **前端友好**: 返回的嵌套结构清晰,循环日志和子块日志自然组织在一起
4. **可扩展性**: `log_type` 字段便于未来扩展其他类型的日志
5. **向后兼容**: 保留旧版本逻辑,可通过参数切换
## 测试建议
1. **功能测试**:
- 执行简单循环任务(1层循环)
- 执行嵌套循环任务(2-3层循环)
- 验证返回的层级结构正确
2. **性能测试**:
- 对比新旧版本的查询性能
- 测试大量循环(>100次)的场景
3. **边界测试**:
- 空循环(数组为空)
- 循环中断(break)
- 循环失败(子块报错)
## 后续优化
1. 为其他循环块(`WhileBlockHandler`, `RepeatNumBlockHandler`)应用相同逻辑
2. 考虑为条件分支(`IfBlockHandler`)也记录分支信息
3. 添加日志清理策略(历史数据归档)