Files
ai-agent/workflow/dao/flow/flow_async_task_dao.go
T

101 lines
4.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package flow
import (
"ai-agent/workflow/consts/public"
"ai-agent/workflow/model/entity"
"context"
"fmt"
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
)
const (
FlowAsyncStateInflight = 0 // 任务已提交,结果未取(执行中/结果已发布未取/失败)
FlowAsyncStateDone = 1 // 成功,结果已缓存
FlowAsyncStateFailed = 2 // 确定失败
FlowAsyncSegSentinel = -1 // 非段异步调用的段序号哨兵值
)
var FlowAsyncTaskDao = &flowAsyncTaskDao{}
type flowAsyncTaskDao struct{}
// Get 查询唯一键 (execution_id, node_id, segment_index) 的记录
func (d *flowAsyncTaskDao) Get(ctx context.Context, execId int64, nodeId string, segIdx int) (res *entity.FlowAsyncTask, err error) {
r, err := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameFlowAsyncTask).
Where(entity.FlowAsyncTaskCol.ExecutionId, execId).
Where(entity.FlowAsyncTaskCol.NodeId, nodeId).
Where(entity.FlowAsyncTaskCol.SegmentIndex, segIdx).
One()
if err != nil {
return nil, err
}
if r.IsEmpty() {
return nil, nil
}
err = r.Struct(&res)
return
}
// Upsert 提交时写入/更新 in-flight 行:唯一键冲突则更新 model_id/task_id/msg_topic/state(保留已完成结果不动)。
// 与 flow_segment_result 相同走 OnConflict().Save();两点相对初稿的调整:
// 1. Result 列是 JSONB,空串会被 PG 拒绝(invalid input syntax for type json),
// 提交时本无结果,统一写 '{}' 占位(与表列默认值一致)。
// 2. 必须用 OnDuplicate 限定冲突更新列——GoFrame Save 默认把 Data 里所有列写进
// ON CONFLICT DO UPDATE SET,若不限定会把已缓存的结果覆盖成 '{}',与"保留已完成结果"矛盾。
func (d *flowAsyncTaskDao) Upsert(ctx context.Context, execId int64, nodeId string, segIdx int, modelId, taskId int64, msgTopic string) error {
rec := &entity.FlowAsyncTask{
ExecutionId: execId,
NodeId: nodeId,
SegmentIndex: segIdx,
ModelId: modelId,
TaskId: taskId,
MsgTopic: msgTopic,
State: FlowAsyncStateInflight,
Result: "{}",
}
_, err := gfdb.DB(ctx, public.DbNameBlackDeacon).
Model(ctx, public.TableNameFlowAsyncTask).
Data(rec).
OnConflict(entity.FlowAsyncTaskCol.ExecutionId, entity.FlowAsyncTaskCol.NodeId, entity.FlowAsyncTaskCol.SegmentIndex).
OnDuplicate(entity.FlowAsyncTaskCol.ModelId, entity.FlowAsyncTaskCol.TaskId, entity.FlowAsyncTaskCol.MsgTopic, entity.FlowAsyncTaskCol.State).
Save()
return err
}
// UpdateByKey 按唯一键更新 state/resultOmitNil 丢弃 nil 字段,map 值非 nil 全写入;
// state=0 也能落库)。Result 列是 JSONB,空串无法写入,统一落 '{}' 表示无结果。
func (d *flowAsyncTaskDao) UpdateByKey(ctx context.Context, execId int64, nodeId string, segIdx int, state int, result string) error {
resultVal := result
if resultVal == "" {
resultVal = "{}"
}
_, err := gfdb.DB(ctx, public.DbNameBlackDeacon).Model(ctx, public.TableNameFlowAsyncTask).
Where(entity.FlowAsyncTaskCol.ExecutionId, execId).
Where(entity.FlowAsyncTaskCol.NodeId, nodeId).
Where(entity.FlowAsyncTaskCol.SegmentIndex, segIdx).
Data(map[string]any{
entity.FlowAsyncTaskCol.State: state,
entity.FlowAsyncTaskCol.Result: resultVal,
}).
Update()
return err
}
// DeleteByKey 物理删除:实体嵌 SQLBaseDO 软删后同键重存无法复活(ON CONFLICT 不含 deleted_at),
// 与 flow_segment_result 相同约束,须 raw Exec 用物理全名
func (d *flowAsyncTaskDao) DeleteByKey(ctx context.Context, execId int64, nodeId string, segIdx int) error {
const physicalTable = "black_deacon_flow_async_task"
_, err := gfdb.DB(ctx, public.DbNameBlackDeacon).
Exec(ctx, fmt.Sprintf("DELETE FROM %s WHERE execution_id = ? AND node_id = ? AND segment_index = ?", physicalTable), execId, nodeId, segIdx)
return err
}
// DeleteByExecution 清理指定执行的异步任务缓存(exec 成功后调用,与段清理同处)
func (d *flowAsyncTaskDao) DeleteByExecution(ctx context.Context, execId int64) error {
const physicalTable = "black_deacon_flow_async_task"
_, err := gfdb.DB(ctx, public.DbNameBlackDeacon).
Exec(ctx, fmt.Sprintf("DELETE FROM %s WHERE execution_id = ?", physicalTable), execId)
return err
}