feat(workflow-run): 实现执行记录 CRUD 服务与 API - #176
Merged
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
xiaocheny214
requested review from
huyanxius,
johnnyzhang-eng,
minorcell,
nighca and
xyh202131
August 10, 2026 03:41
huyanxius
previously approved these changes
Aug 10, 2026
Collaborator
|
等等,发现个问题 |
huyanxius
reviewed
Aug 10, 2026
xiaocheny214
force-pushed
the
feat/workflow-run
branch
from
August 10, 2026 06:13
9ad72d5 to
ea24946
Compare
Collaborator
|
没问题,可以合并 |
nighca
approved these changes
Aug 10, 2026
huyanxius
approved these changes
Aug 10, 2026
johnnyzhang-eng
added a commit
to johnnyzhang-eng/game-asset-character
that referenced
this pull request
Aug 10, 2026
按 1024XEngineer#151 / 1024XEngineer#152 的内容迁到当前 main(efd230e)之上重提。主线上 orchestrator 只有 interface + model,缺 service / executor / task_repo;generation API 三个端点是 「接口待实现」。 ## 迁移时按主线现状做的调整 **接口签名统一到 session-per-call。** 主线 orchestrator/interface.py 的三个方法没有 session 参数,而 1024XEngineer#176 刚合入的 workflow_run/service.py 用的是「session 首参 + 关键字 入参 + 只 flush 不 commit」。两处不一致会让同一个仓里出现两种事务写法,故 orchestrator 跟上已确立的那套;事务边界仍归 windup_framework.db.get_session。 **保留主线的 SSE 文档与终态关流。** interface.py 的 SSE 契约说明、generation.py 的 _TERMINAL_EVENTS 与终态后 break,都是主线后来加的,比源分支的「前端轮询」更准确, 原样保留。终态关流治的是:服务端发完 task_update 就关流但带 retry: 3000,浏览器原生 EventSource 每 3 秒重连、45 秒内 15 次,每次重收同一条 completed。 **user_id 从 JWT 取,不信客户端。** 源分支的请求体里有 user_id: int = Field(gt=0), 客户端可以填别人的 id。改为 request.state.current_user.id,并加项目归属校验 (项目不存在或不属于当前用户一律 404,不区分两者以免泄露他人项目是否存在)。 ## 后台执行的两处竞态与分层 **after_commit 再起线程。** create_task 只 flush,session 要等 handler 返回后才 commit。 直接起线程的话,后台 session 可能读不到未提交的任务行,update 静默跳过——任务永远停在 PENDING 且无任何报错。改为注册 after_commit 回调,提交成功后才派发。 **executor 挂 app.state,不 import 进 web 层。** import-linter 的分层契约禁止 app.web 直连 ai_engine,而 executor 要调 ai_engine.impl。放进 state 由 bootstrap (唯一装配点)注入,契约与实现两边都成立。 ## 依赖链 orchestrator/executor.py import 了 windup_ai_engine.{impl,ports,strategy.concrete} 与 windup_common.models,四层里主线只有 windup_framework.providers。故本分支 stack 在 ai_engine 那条线之上,那条合入后 rebase。 Refs 1024XEngineer#171
johnnyzhang-eng
added a commit
to johnnyzhang-eng/game-asset-character
that referenced
this pull request
Aug 10, 2026
按 1024XEngineer#151 / 1024XEngineer#152 的内容迁到当前 main(efd230e)之上重提。主线上 orchestrator 只有 interface + model,缺 service / executor / task_repo;generation API 三个端点是 「接口待实现」。 ## 迁移时按主线现状做的调整 **接口签名统一到 session-per-call。** 主线 orchestrator/interface.py 的三个方法没有 session 参数,而 1024XEngineer#176 刚合入的 workflow_run/service.py 用的是「session 首参 + 关键字 入参 + 只 flush 不 commit」。两处不一致会让同一个仓里出现两种事务写法,故 orchestrator 跟上已确立的那套;事务边界仍归 windup_framework.db.get_session。 **保留主线的 SSE 文档与终态关流。** interface.py 的 SSE 契约说明、generation.py 的 _TERMINAL_EVENTS 与终态后 break,都是主线后来加的,比源分支的「前端轮询」更准确, 原样保留。终态关流治的是:服务端发完 task_update 就关流但带 retry: 3000,浏览器原生 EventSource 每 3 秒重连、45 秒内 15 次,每次重收同一条 completed。 **user_id 从 JWT 取,不信客户端。** 源分支的请求体里有 user_id: int = Field(gt=0), 客户端可以填别人的 id。改为 request.state.current_user.id,并加项目归属校验 (项目不存在或不属于当前用户一律 404,不区分两者以免泄露他人项目是否存在)。 ## 后台执行的两处竞态与分层 **after_commit 再起线程。** create_task 只 flush,session 要等 handler 返回后才 commit。 直接起线程的话,后台 session 可能读不到未提交的任务行,update 静默跳过——任务永远停在 PENDING 且无任何报错。改为注册 after_commit 回调,提交成功后才派发。 **executor 挂 app.state,不 import 进 web 层。** import-linter 的分层契约禁止 app.web 直连 ai_engine,而 executor 要调 ai_engine.impl。放进 state 由 bootstrap (唯一装配点)注入,契约与实现两边都成立。 ## 依赖链 orchestrator/executor.py import 了 windup_ai_engine.{impl,ports,strategy.concrete} 与 windup_common.models,四层里主线只有 windup_framework.providers。故本分支 stack 在 ai_engine 那条线之上,那条合入后 rebase。 Refs 1024XEngineer#171
johnnyzhang-eng
added a commit
to johnnyzhang-eng/game-asset-character
that referenced
this pull request
Aug 10, 2026
按 1024XEngineer#151 / 1024XEngineer#152 的内容迁到当前 main(efd230e)之上重提。主线上 orchestrator 只有 interface + model,缺 service / executor / task_repo;generation API 三个端点是 「接口待实现」。 ## 迁移时按主线现状做的调整 **接口签名统一到 session-per-call。** 主线 orchestrator/interface.py 的三个方法没有 session 参数,而 1024XEngineer#176 刚合入的 workflow_run/service.py 用的是「session 首参 + 关键字 入参 + 只 flush 不 commit」。两处不一致会让同一个仓里出现两种事务写法,故 orchestrator 跟上已确立的那套;事务边界仍归 windup_framework.db.get_session。 **保留主线的 SSE 文档与终态关流。** interface.py 的 SSE 契约说明、generation.py 的 _TERMINAL_EVENTS 与终态后 break,都是主线后来加的,比源分支的「前端轮询」更准确, 原样保留。终态关流治的是:服务端发完 task_update 就关流但带 retry: 3000,浏览器原生 EventSource 每 3 秒重连、45 秒内 15 次,每次重收同一条 completed。 **user_id 从 JWT 取,不信客户端。** 源分支的请求体里有 user_id: int = Field(gt=0), 客户端可以填别人的 id。改为 request.state.current_user.id,并加项目归属校验 (项目不存在或不属于当前用户一律 404,不区分两者以免泄露他人项目是否存在)。 ## 后台执行的两处竞态与分层 **after_commit 再起线程。** create_task 只 flush,session 要等 handler 返回后才 commit。 直接起线程的话,后台 session 可能读不到未提交的任务行,update 静默跳过——任务永远停在 PENDING 且无任何报错。改为注册 after_commit 回调,提交成功后才派发。 **executor 挂 app.state,不 import 进 web 层。** import-linter 的分层契约禁止 app.web 直连 ai_engine,而 executor 要调 ai_engine.impl。放进 state 由 bootstrap (唯一装配点)注入,契约与实现两边都成立。 ## 依赖链 orchestrator/executor.py import 了 windup_ai_engine.{impl,ports,strategy.concrete} 与 windup_common.models,四层里主线只有 windup_framework.providers。故本分支 stack 在 ai_engine 那条线之上,那条合入后 rebase。 Refs 1024XEngineer#171
johnnyzhang-eng
added a commit
to johnnyzhang-eng/game-asset-character
that referenced
this pull request
Aug 11, 2026
按 1024XEngineer#151 / 1024XEngineer#152 的内容迁到当前 main(efd230e)之上重提。主线上 orchestrator 只有 interface + model,缺 service / executor / task_repo;generation API 三个端点是 「接口待实现」。 ## 迁移时按主线现状做的调整 **接口签名统一到 session-per-call。** 主线 orchestrator/interface.py 的三个方法没有 session 参数,而 1024XEngineer#176 刚合入的 workflow_run/service.py 用的是「session 首参 + 关键字 入参 + 只 flush 不 commit」。两处不一致会让同一个仓里出现两种事务写法,故 orchestrator 跟上已确立的那套;事务边界仍归 windup_framework.db.get_session。 **保留主线的 SSE 文档与终态关流。** interface.py 的 SSE 契约说明、generation.py 的 _TERMINAL_EVENTS 与终态后 break,都是主线后来加的,比源分支的「前端轮询」更准确, 原样保留。终态关流治的是:服务端发完 task_update 就关流但带 retry: 3000,浏览器原生 EventSource 每 3 秒重连、45 秒内 15 次,每次重收同一条 completed。 **user_id 从 JWT 取,不信客户端。** 源分支的请求体里有 user_id: int = Field(gt=0), 客户端可以填别人的 id。改为 request.state.current_user.id,并加项目归属校验 (项目不存在或不属于当前用户一律 404,不区分两者以免泄露他人项目是否存在)。 ## 后台执行的两处竞态与分层 **after_commit 再起线程。** create_task 只 flush,session 要等 handler 返回后才 commit。 直接起线程的话,后台 session 可能读不到未提交的任务行,update 静默跳过——任务永远停在 PENDING 且无任何报错。改为注册 after_commit 回调,提交成功后才派发。 **executor 挂 app.state,不 import 进 web 层。** import-linter 的分层契约禁止 app.web 直连 ai_engine,而 executor 要调 ai_engine.impl。放进 state 由 bootstrap (唯一装配点)注入,契约与实现两边都成立。 ## 依赖链 orchestrator/executor.py import 了 windup_ai_engine.{impl,ports,strategy.concrete} 与 windup_common.models,四层里主线只有 windup_framework.providers。故本分支 stack 在 ai_engine 那条线之上,那条合入后 rebase。 Refs 1024XEngineer#171
johnnyzhang-eng
added a commit
to johnnyzhang-eng/game-asset-character
that referenced
this pull request
Aug 11, 2026
按 1024XEngineer#151 / 1024XEngineer#152 的内容迁到当前 main(efd230e)之上重提。主线上 orchestrator 只有 interface + model,缺 service / executor / task_repo;generation API 三个端点是 「接口待实现」。 ## 迁移时按主线现状做的调整 **接口签名统一到 session-per-call。** 主线 orchestrator/interface.py 的三个方法没有 session 参数,而 1024XEngineer#176 刚合入的 workflow_run/service.py 用的是「session 首参 + 关键字 入参 + 只 flush 不 commit」。两处不一致会让同一个仓里出现两种事务写法,故 orchestrator 跟上已确立的那套;事务边界仍归 windup_framework.db.get_session。 **保留主线的 SSE 文档与终态关流。** interface.py 的 SSE 契约说明、generation.py 的 _TERMINAL_EVENTS 与终态后 break,都是主线后来加的,比源分支的「前端轮询」更准确, 原样保留。终态关流治的是:服务端发完 task_update 就关流但带 retry: 3000,浏览器原生 EventSource 每 3 秒重连、45 秒内 15 次,每次重收同一条 completed。 **user_id 从 JWT 取,不信客户端。** 源分支的请求体里有 user_id: int = Field(gt=0), 客户端可以填别人的 id。改为 request.state.current_user.id,并加项目归属校验 (项目不存在或不属于当前用户一律 404,不区分两者以免泄露他人项目是否存在)。 ## 后台执行的两处竞态与分层 **after_commit 再起线程。** create_task 只 flush,session 要等 handler 返回后才 commit。 直接起线程的话,后台 session 可能读不到未提交的任务行,update 静默跳过——任务永远停在 PENDING 且无任何报错。改为注册 after_commit 回调,提交成功后才派发。 **executor 挂 app.state,不 import 进 web 层。** import-linter 的分层契约禁止 app.web 直连 ai_engine,而 executor 要调 ai_engine.impl。放进 state 由 bootstrap (唯一装配点)注入,契约与实现两边都成立。 ## 依赖链 orchestrator/executor.py import 了 windup_ai_engine.{impl,ports,strategy.concrete} 与 windup_common.models,四层里主线只有 windup_framework.providers。故本分支 stack 在 ai_engine 那条线之上,那条合入后 rebase。 Refs 1024XEngineer#171
johnnyzhang-eng
added a commit
to johnnyzhang-eng/game-asset-character
that referenced
this pull request
Aug 11, 2026
按 1024XEngineer#151 / 1024XEngineer#152 的内容迁到当前 main(efd230e)之上重提。主线上 orchestrator 只有 interface + model,缺 service / executor / task_repo;generation API 三个端点是 「接口待实现」。 ## 迁移时按主线现状做的调整 **接口签名统一到 session-per-call。** 主线 orchestrator/interface.py 的三个方法没有 session 参数,而 1024XEngineer#176 刚合入的 workflow_run/service.py 用的是「session 首参 + 关键字 入参 + 只 flush 不 commit」。两处不一致会让同一个仓里出现两种事务写法,故 orchestrator 跟上已确立的那套;事务边界仍归 windup_framework.db.get_session。 **保留主线的 SSE 文档与终态关流。** interface.py 的 SSE 契约说明、generation.py 的 _TERMINAL_EVENTS 与终态后 break,都是主线后来加的,比源分支的「前端轮询」更准确, 原样保留。终态关流治的是:服务端发完 task_update 就关流但带 retry: 3000,浏览器原生 EventSource 每 3 秒重连、45 秒内 15 次,每次重收同一条 completed。 **user_id 从 JWT 取,不信客户端。** 源分支的请求体里有 user_id: int = Field(gt=0), 客户端可以填别人的 id。改为 request.state.current_user.id,并加项目归属校验 (项目不存在或不属于当前用户一律 404,不区分两者以免泄露他人项目是否存在)。 ## 后台执行的两处竞态与分层 **after_commit 再起线程。** create_task 只 flush,session 要等 handler 返回后才 commit。 直接起线程的话,后台 session 可能读不到未提交的任务行,update 静默跳过——任务永远停在 PENDING 且无任何报错。改为注册 after_commit 回调,提交成功后才派发。 **executor 挂 app.state,不 import 进 web 层。** import-linter 的分层契约禁止 app.web 直连 ai_engine,而 executor 要调 ai_engine.impl。放进 state 由 bootstrap (唯一装配点)注入,契约与实现两边都成立。 ## 依赖链 orchestrator/executor.py import 了 windup_ai_engine.{impl,ports,strategy.concrete} 与 windup_common.models,四层里主线只有 windup_framework.providers。故本分支 stack 在 ai_engine 那条线之上,那条合入后 rebase。 Refs 1024XEngineer#171
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
实现工作流执行记录(WorkflowRun)的完整 CRUD,为工作流节点编排和前端画布提供持久化层。
包含内容
模型层(server/workflow_run/model.py)
windup_workflow_run表)nodes字段:JSONB(Postgres)/ JSON(SQLite),前端自定义结构,后端不校验status字段:active/soft_deletedversion字段:每次更新自增,支持乐观并发服务层(server/workflow_run/service.py)
SqlAlchemyWorkflowRunService:实现WorkflowRunService接口create_run/get_run/list_runs(分页) /update_run/delete_run(软删除)API 层(web/api/workflow_run.py)
POST /workflow-runs— 创建GET /workflow-runs?project_id=...— 分页列表(排除软删除)GET /workflow-runs/{id}— 详情PATCH /workflow-runs/{id}— 全量更新 nodes / statusDELETE /workflow-runs/{id}— 软删除路由注册(bootstrap/app.py)
workflow_run_routerWorkflowRunmodel 触发Base.metadata注册,启动时自动建表测试(17 用例全通过)
关联