并发模型: spawn派发协助分支 + 转交简化为单线 + 子分支未完成拦截(409)

This commit is contained in:
2026-08-05 18:01:14 +08:00
parent b79d521bad
commit b547844dca
4 changed files with 121 additions and 21 deletions

View File

@ -236,6 +236,9 @@ async def end_task(
"""
task = await _get_task_or_404(db, task_id)
# 校验:必须等待所有协助分支完成
await _check_children_done(db, task_id)
if task.status == TASK_STATUS_COMPLETED:
raise HTTPException(status_code=409, detail="此分支已经结束")
if task.status == TASK_STATUS_PENDING:
@ -253,6 +256,62 @@ async def end_task(
return _to_response(task)
# ============================================================
# 核心业务 0.5:派发协助分支(不改变父任务状态)
# ============================================================
async def spawn_subtask(
db: AsyncSession, task_id: uuid.UUID, data, operator_id: str | None = None
) -> TaskResponse:
"""在当前任务下创建并行子任务,父任务状态保持不变。"""
task = await _get_task_or_404(db, task_id)
if task.status == TASK_STATUS_COMPLETED:
raise HTTPException(status_code=409, detail="任务已完成,无法派发协助分支")
if task.status == TASK_STATUS_REJECTED:
raise HTTPException(status_code=409, detail="任务已驳回,无法派发协助分支")
child = Task(
product_id=task.product_id,
parent_task_id=task.id,
task_name=data.task_name,
assignee_id=data.assignee_id,
status=TASK_STATUS_PENDING,
notify_parent_on_complete=False,
is_rework=False,
remark=data.remark or None,
)
db.add(child)
await db.flush()
await _create_task_log(db, child.id, action_type="create", operator_id=operator_id,
remark=f"协助分支(由「{task.task_name}」派发,分配给 {data.assignee_id}")
await db.commit()
await db.refresh(child)
return _to_response(child)
async def _check_children_done(db: AsyncSession, task_id: uuid.UUID):
"""检查当前任务的所有子任务是否都已完结。未完结则抛出 409。"""
result = await db.execute(
select(Task).where(Task.parent_task_id == task_id)
)
children = result.scalars().all()
incomplete = [c for c in children if c.status not in (
TASK_STATUS_COMPLETED, TASK_STATUS_REJECTED, ARCHIVED_STATUS
)]
if incomplete:
names = "".join(c.task_name for c in incomplete)
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=f"当前工序还有未完成的协助分支({names}),必须等待分支结束才能转交或完工!",
)
return True
ARCHIVED_STATUS = "ARCHIVED"
# ============================================================
# 核心业务 1确认接收 (PENDING → WIP)
# ============================================================
@ -429,6 +488,9 @@ async def transfer_task(
"""
task = await _get_task_or_404(db, task_id)
# 校验:必须等待所有协助分支完成
await _check_children_done(db, task_id)
# 校验:不能重复完成
if task.status == TASK_STATUS_COMPLETED:
raise HTTPException(