7.6 KiB
7.6 KiB
任务日志层级关系优化方案
改造背景
原有问题
- 日志表缺少层级关系字段:
vwed_tasklog表只有基本字段,没有记录父子关系、迭代索引等信息 - 层级重构困难:
get_block_results接口需要解析日志中的 JSONoutput.iterationResults来重构层级,不稳定 - 循环日志分散: 循环块的日志("第1次循环")和子块执行日志是分开的,前端难以组织嵌套显示
期望效果
对于循环任务,期望返回的数据结构为:
{
"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
执行迁移:
cd /mnt/d/jsw_code/project/VWED_server
alembic upgrade head
2. 日志记录逻辑改造
TaskContext 扩展
在 services/execution/task_context.py 中添加:
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 方法:
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 的迭代处理逻辑中:
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,实现基于层级关系字段的查询逻辑:
核心思路:
-
构建映射表:
log_map_by_block: 按块名称分组日志log_map_by_parent: 按父日志ID分组子日志
-
识别迭代块:
- 检查
block_type是否为ITERATE_LIST,WHILE,REPEAT_NUM - 找出所有
log_type="iteration_start"的日志
- 检查
-
按迭代组织:
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, []) # ... 递归构建子块 -
递归处理嵌套:
- 如果子块也是迭代块,继续应用相同逻辑
- 普通块直接递归处理其子块
兼容旧版本
在 services/task_record_service.py 中:
@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解析)
数据流示例
任务定义
{
"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 |
查询结果组织
{
"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"}
]
}
]
}
]
}
优势
- 数据完整性: 日志记录时就建立层级关系,不依赖运行时的内存状态
- 查询性能: 通过索引直接查询层级关系,无需解析JSON
- 前端友好: 返回的嵌套结构清晰,循环日志和子块日志自然组织在一起
- 可扩展性:
log_type字段便于未来扩展其他类型的日志 - 向后兼容: 保留旧版本逻辑,可通过参数切换
测试建议
-
功能测试:
- 执行简单循环任务(1层循环)
- 执行嵌套循环任务(2-3层循环)
- 验证返回的层级结构正确
-
性能测试:
- 对比新旧版本的查询性能
- 测试大量循环(>100次)的场景
-
边界测试:
- 空循环(数组为空)
- 循环中断(break)
- 循环失败(子块报错)
后续优化
- 为其他循环块(
WhileBlockHandler,RepeatNumBlockHandler)应用相同逻辑 - 考虑为条件分支(
IfBlockHandler)也记录分支信息 - 添加日志清理策略(历史数据归档)