任务执行架构
当前执行分层
当前长耗时任务执行采用两层结构:
业务任务真相层
├── GenerationTask
├── GenerationTaskLink
├── /api/v1/film/tasks
├── /api/v1/film/tasks/{task_id}/status
└── /api/v1/film/tasks/{task_id}/result
执行层
├── FastAPI 负责创建任务与返回 task_id
├── Redis 作为 Celery broker
└── Celery Worker 执行长耗时任务
执行协议层
├── GenerationTask.task_kind
├── task.execute(统一 Celery 入口)
└── TaskExecutorRegistry(task_kind → executor)
运行时分层
├── Web Runtime
│ ├── async SQLAlchemy
│ └── FastAPI dependencies
└── Worker Runtime
├── sync SQLAlchemy
└── Celery task wrappers + worker services约束如下:
GenerationTask仍是任务状态、结果、错误与取消请求的唯一真相源/api/v1/film/tasks当前作为前端全局任务中心的主数据源GenerationTaskLink当前承担任务与业务实体的关联信息查询GenerationTask当前也记录运行时指标:started_at、finished_at- 任务状态接口当前直接暴露:
started_at_tsfinished_at_tselapsed_ms
- 前端不直接读取 Celery task 状态
- Celery 只负责执行,不负责对前端暴露业务状态
- 任务投递统一使用
task_kind识别具体执行器
全局任务列表接口当前规则:
- 默认返回:
- 活跃任务(
pending / running / streaming) - 最近结束的任务(按
recent_seconds控制)
- 活跃任务(
- 支持按以下维度过滤:
statusestask_kindrelation_typerelation_entity_id
- 返回项同时包含:
- 任务状态与进度
- started / finished / elapsed 指标
- executor 信息
- relation 信息
- 前端默认导航对象信息(用于任务中心回到对应章节/镜头/资产)
当前前端任务中心以该接口为主列表来源,页面自身只补充:
- 当前页面关联对象的高亮上下文
- 任务标题、来源、跳转等即时 UI 元信息
当前基础设施
当前最小执行层方案为:
业务库:MySQL
Broker:Redis
执行器:Celery Worker配置规则:
DATABASE_URL继续指向 MySQLCELERY_BROKER_URL若未显式指定,则按 Redis 配置自动拼接backend/.env由app.config按绝对路径加载,避免 worker 因工作目录变化回退到默认 SQLite
已切到 Celery 的任务
当前已从本地 asyncio.create_task(...) 切到 Celery worker 的任务包括:
divideextractcheck-consistencyoptimize-scriptsimplify-scriptanalyze-character-portraitanalyze-prop-infoanalyze-scene-infoanalyze-costume-infoimage-generationvideo-generationshot-frame-prompt
其中又分两类:
已切到 sync worker runtime
divideextractcheck-consistencyoptimize-scriptsimplify-scriptanalyze-character-portraitanalyze-prop-infoanalyze-scene-infoanalyze-costume-info
这些任务当前通过:
db_sync.pySyncSqlAlchemyTaskStore- worker 专用同步 LLM runtime
script_processing_worker.py
执行,不再在 Celery worker 中承载 async DB runtime。
已切到 async delegating executor
image-generationvideo-generationshot-frame-prompt
这些任务当前也通过 task.execute(task_id) 进入统一 Celery 执行层,
但执行器使用 AbstractAsyncDelegatingExecutor 作为桥接:
- 每次任务执行前重建 async DB runtime
- 在独立 event loop 中运行既有 async service
- 任务结束后主动释放 async engine
- 在执行前、结果生成后、结果持久化后执行统一取消检查
- 通过 executor 统一配置任务超时
- 输出统一任务事件日志(started / running / cancelled / succeeded / failed)
这样可以先把执行从 Web 进程迁出,同时保持图片 / 视频 provider 调用链的现有 async 实现。
当前这三类 async worker 已补最小专项测试,重点锁定:
- 启动前取消请求会直接转
cancelled - 不再进入后续 provider / agent 调用
当前 Celery 主链路特征
当前主链采用:
- API 层创建
GenerationTask - API 层写入
task_kind - 通过
spawn_*_task(...)投递到 Celery - Celery 统一走
task.execute(task_id) - worker 通过
TaskExecutorRegistry按task_kind路由到具体WorkerTaskExecutor - worker 执行后把状态与结果回写到 MySQL
- 页面继续通过既有任务状态接口轮询和恢复
对核心任务(如 divide)进一步采用两阶段模型:
阶段 A:生成结果
→ 调 LLM / Agent
→ GenerationTask.result
阶段 B:应用结果
→ 写业务表
→ 更新业务状态当前有真实前端入口的 script-processing 文本任务,已统一挂到:
AbstractWorkerTaskExecutorAbstractLLMResultGeneratorTaskExecutorRegistry
其中 sync executor 当前提供:
- 统一 started / succeeded / failed / cancelled 日志
- 统一阶段边界超时检查
这里的超时语义是“阶段边界超时”,不是执行中强中断:
- 在进入执行前检查
- 在生成结果后检查
- 在 apply 后检查
当前已模板化的 executor 包括:
script_dividescript_extractscript_consistencyscript_character_portraitscript_prop_infoscript_scene_infoscript_costume_infoscript_optimizescript_simplify
当前已接入 registry 的非文本生成 executor 包括:
image_generationvideo_generationshot_frame_prompt
当前前端任务状态展示
当前前端任务状态展示采用“页面局部反馈 + 轻量全局提示”:
旧的页面内大块任务提示组件已退出主流程,不再作为默认交互形态
触发任务的按钮负责:
loading- 防重复点击
- 帮助用户确认是哪个动作正在运行
任务详情通过 Notification 展示:
- 当前状态
- 进度
- 开始时间
- 已运行/累计耗时
- 任务结束后的成功、失败、取消反馈
- 支持直接跳回来源页面
取消入口当前优先放在:
- 触发区域旁的轻量按钮
- Notification 内的小型取消动作
悬浮任务中心当前统一展示全局任务列表:
- 默认隐藏,是否展开会按本地历史状态恢复
- 首次进入时,悬浮按钮默认位于左下角
- 浮动按钮支持在视窗范围内拖动,并在拖动结束后自动吸附到左侧或右侧边缘
- 悬浮按钮会记住最近一次位置
- 展开面板会根据按钮位置自动调整展开方向与对齐方式,避免超出当前视窗
- 查看当前运行中的任务
- 查看最近刚结束的任务
- 显示任务所属对象或来源页面
- 查看进度、开始时间和耗时
- 统一执行取消操作
- 支持回到对应来源页面
- 任务结束后会短暂保留,便于确认刚刚的执行结果
- 支持按当前页面 / 运行中 / 最近结束与任务类型做轻量筛选
- 面板保持轻量化,当前每页最多展示 3 条任务
- 翻页使用紧凑箭头控件,不引入大体积分页栏
当前页面只负责向任务中心提供“高亮哪些任务与当前对象有关”的上下文,不再决定任务是否存在
当前页面高亮匹配当前优先使用任务的默认导航对象:
navigate_relation_typenavigate_relation_entity_id- 若后端未返回导航对象,再回退到原始
relation_type + relation_entity_id
对未由当前页面显式补充来源信息的任务,任务中心会按:
relation_type + relation_entity_id- 自动解析默认来源文案
- 尽量推导默认查看跳转
主要异步任务的启动、运行中、取消和结束态提示文案已统一收口:
- 同类任务在不同页面保持一致语气
- 后续新增任务应复用同一套文案配置
当前图片生成页与分镜工作室中的生成动作,也已接入同一套 Notification / 任务中心桥接:
- 不再只依赖页面内
message + 手写轮询 - 会同步出现在统一任务反馈链路中
- 不再只依赖页面内
当前已经从页面内大块提示切到这套较轻交互的页面包括:
- 分镜管理页
- 分镜编辑页
- 分镜工作室
- 原文编辑弹窗
- 资产编辑页
- 项目工作台章节列表中的分镜提取入口
当前仍未切到 Celery 的任务
以下任务当前仍保留旧执行方式,且当前没有真实前端主入口,因此不作为主线优先项:
merge-entitiesanalyze-variants
它们虽然已纳入任务模型,但当前仍属于预备能力。
取消语义
当前取消采用“两级取消”:
前端请求取消
→ GenerationTask.cancel_requested = true
→ 若任务由 Celery 执行且存在 executor_task_id:
→ 立即下发 revoke(terminate=True)
→ API 直接把业务任务状态推进到 cancelled
→ 若无法立即终止:
→ worker 在阶段边界继续执行协作式取消这意味着:
- 对已进入 Celery worker 的任务,当前支持 best-effort 的“立即取消”
- 对无法立即终止的单次长调用,仍保留阶段边界协作式取消作为兜底
- 当前不承诺 provider / LLM SDK 层面的绝对强终止,只保证业务任务状态会立即收敛
服务层约束
当前任务执行链要求遵守以下约束:
service层不得反向依赖api.v1.routes- Celery task wrapper 只做 task_id 投递
- worker 侧执行逻辑放在
app.services.script_processing_worker - Web 侧任务创建与状态恢复逻辑保留在
app.services.script_processing_tasks
这条约束已经用于修复 worker 下暴露出的循环导入问题。