feat(workflow): 增加工作流计费与执行生命周期管理
- 新增计费模块:执行开始建单、终态结算/取消/失败处理,支持按条/按秒/按token计费 - 新增执行生命周期跟踪:优雅关停时取消运行中执行并等待落库 - 新增异步任务等待/通知机制(Wait/Notify) - 重构执行记录落库与进度上报,统一失败分类与重试语义 - 重命名文件:async_task.go→async.go、flow_checkpoint_store.go→exec_checkpoint.go、flow_graph_util.go→exec_record.go - 更新 .gitignore 与数据库密码配置
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
commonHttp "gitea.redpowerfuture.com/red-future/common/http"
|
||||
"gitea.redpowerfuture.com/red-future/common/oss"
|
||||
"gitea.redpowerfuture.com/red-future/common/utils"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
@@ -158,7 +159,7 @@ func SubmitMergeAsync(ctx context.Context, videoURLs, audioURLs []string, upload
|
||||
func submitMediaTask(ctx context.Context, kind TaskKind, req *mergeSubmitReq) (string, error) {
|
||||
path := "media/video/" + string(kind) + "/async"
|
||||
res := new(mergeSubmitRes)
|
||||
if err := commonHttp.Post(ctx, path, requestHeaders(ctx), res, req); err != nil {
|
||||
if err := commonHttp.Post(ctx, path, utils.HeadersFromCtx(ctx), res, req); err != nil {
|
||||
return "", fmt.Errorf("提交%s任务失败: %v", kind, err)
|
||||
}
|
||||
if res.TaskID == "" {
|
||||
@@ -199,31 +200,12 @@ func WaitMediaTask(ctx context.Context, kind TaskKind, taskID string, timeout ti
|
||||
func getMediaTask(ctx context.Context, kind TaskKind, taskID string) (*MergeTask, error) {
|
||||
path := "media/video/" + string(kind) + "/task/" + taskID
|
||||
res := new(MergeTask)
|
||||
if err := commonHttp.Get(ctx, path, requestHeaders(ctx), res); err != nil {
|
||||
if err := commonHttp.Get(ctx, path, utils.HeadersFromCtx(ctx), res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// requestHeaders 透传当前请求头(含 Authorization / X-User-Info),供内部服务鉴权使用;
|
||||
// 后台恢复续跑无 HTTP 请求时(ctx 携带合成 user),补充 X-User-Info 供下游 GetUserInfo 识别租户
|
||||
func requestHeaders(ctx context.Context) map[string]string {
|
||||
headers := make(map[string]string)
|
||||
if r := g.RequestFromCtx(ctx); r != nil {
|
||||
for k, v := range r.Request.Header {
|
||||
if len(v) > 0 {
|
||||
headers[k] = v[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
if headers["X-User-Info"] == "" {
|
||||
if u := ctx.Value("user"); u != nil {
|
||||
headers["X-User-Info"] = gconv.String(u)
|
||||
}
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
// segmentResult 一段视频生成的产出(原 ai-agent/video/plan.SegmentResult,plan 包已并入处理器树)。
|
||||
type segmentResult struct {
|
||||
SegmentIndex int `json:"segment_index"`
|
||||
|
||||
Reference in New Issue
Block a user