触发机制补两条(见 docs/planner-trigger-impl-plan.md): 1) finding 当场唤醒:worker 飞行中 report_finding 落库即唤醒本任务 planner, 不再等 worker 整趟收工才反应。 - worker.Execute 加 notify 入参并 SetNotify(补上 worker toolset 之前缺失的接线) - addFinding 写 KindFinding 成功后调 notify(只对 finding,不对 fact) - engine 两处 worker.Execute 调用传 t.Notify 2) planner N 秒心跳:距上轮规划结束/任务开始满 N 秒且期间无触发 → 触发一轮, 兜底卡死 + 唤醒去监督飞行中的 worker(steer/kill) + 周期复查。 - plannerLoop 重构为 runRound 闭包 + 三臂 select(ctx/notify/heartbeat) - 心跳在 loop 入口臂 = 从任务 start 计时(覆盖 seed 跳过首轮),每轮结束重臂 - 新增任务参数 plan_heartbeat_seconds,下限=默认=300(5min),低于自动抬到300 - DB 迁移:schema.sql 加列 + ALTER ADD COLUMN IF NOT EXISTS 补旧库 - 全链路接线:db.CreateTask/manager/server HTTP/orchestration spawn_task - 前端:api.createTask 传参 + 建任务表单新增"planner 心跳(分钟)"字段
61 lines
1.4 KiB
Go
61 lines
1.4 KiB
Go
package db
|
|
|
|
import "testing"
|
|
|
|
func TestTaskLifecycleAndDeleteCascade(t *testing.T) {
|
|
d, err := Open(testDSN(t))
|
|
if err != nil {
|
|
t.Skipf("postgres unavailable (%v) — skipping", err)
|
|
}
|
|
defer d.Close()
|
|
|
|
tk, err := d.CreateTask("迁移测试", "目标X", nil, 0, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// populate the exploration subgraph
|
|
es := d.Exploration(tk.ExplorationID)
|
|
if _, err := es.AddIntent(map[string]any{"summary": "x"}, 5, nil, "planner"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// pause + status
|
|
if err := d.SetPaused(tk.ID, true); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := d.GetTask(tk.ID)
|
|
if err != nil || got == nil || !got.Paused {
|
|
t.Fatalf("paused not persisted: %+v err=%v", got, err)
|
|
}
|
|
|
|
// list contains it
|
|
list, _ := d.ListTasks()
|
|
found := false
|
|
for _, x := range list {
|
|
if x.ID == tk.ID {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatalf("task not in list")
|
|
}
|
|
|
|
// delete cascades exploration subgraph
|
|
if err := d.DeleteTask(tk.ID); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if g, _ := d.GetTask(tk.ID); g != nil {
|
|
t.Fatalf("task should be gone")
|
|
}
|
|
var nodes int
|
|
d.QueryRow(`SELECT count(*) FROM exploration_nodes WHERE exploration_id=$1`, tk.ExplorationID).Scan(&nodes)
|
|
if nodes != 0 {
|
|
t.Fatalf("exploration nodes should be cascade-deleted, got %d", nodes)
|
|
}
|
|
var exps int
|
|
d.QueryRow(`SELECT count(*) FROM explorations WHERE id=$1`, tk.ExplorationID).Scan(&exps)
|
|
if exps != 0 {
|
|
t.Fatalf("exploration should be deleted, got %d", exps)
|
|
}
|
|
}
|