ci / vet-and-test (pull_request) Successful in 42s
Why: deliverNotices re-invoked itself synchronously from a defer after a failed startNoticeRun requeued the batch - a persistently failing delivery (busy conversation, missing row, slow DB) recursed without bound and overflowed the stack (real-PG CI job 2352, internal/runmgr). Evidence: regression test TestNoticeDeliveryFailureIsBounded (missing conversation row) hangs on the old code and passes with the fix; full backend suite green on SQLite and against real PostgreSQL 18.6 + Redis; clean-HEAD reproduction isolated an unrelated count=2 admin-login artifact. Impact: failed batches now return after requeue (retried on the next enqueue or restart); notices arriving during delivery are picked up by a bounded loop tail instead of defer recursion; no behavior change on the success path. Refs: Dev PR #333; plan R8 real-database gate.
47 lines
1.4 KiB
Go
47 lines
1.4 KiB
Go
package runmgr
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"agent-system-backend/internal/store"
|
|
core "agent-system-core"
|
|
)
|
|
|
|
// U3 真库门禁回归(job 2352 栈溢出):投递失败(会话行不存在)时旧实现的
|
|
// defer 同步再入 deliverNotices 无限自递归。修复后:单次有界返回、通知
|
|
// 保留在队列,由下一次触发或重启重投驱动。
|
|
func TestNoticeDeliveryFailureIsBounded(t *testing.T) {
|
|
runner := &gateRunner{parts: []core.Part{{Type: core.PartText, Text: "结果"}}}
|
|
c, _ := newSpawnEnv(t, runner)
|
|
c.mgr.SetWorkspaceRoot(t.TempDir())
|
|
|
|
convID := core.ID(store.NewID("cnv"))
|
|
c.mgr.enqueueNotice(convID, bgNotice{owner: c.run.Owner, name: "检索", payload: core.AgentResultPayload{Status: "completed"}})
|
|
|
|
done := make(chan struct{})
|
|
go func() {
|
|
c.mgr.deliverNotices(convID)
|
|
close(done)
|
|
}()
|
|
select {
|
|
case <-done:
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("deliverNotices 未返回:失败重投仍在递归/自旋")
|
|
}
|
|
c.mgr.noticeMu.Lock()
|
|
queued := len(c.mgr.notices[convID])
|
|
c.mgr.noticeMu.Unlock()
|
|
if queued != 1 {
|
|
t.Fatalf("失败应保留待投通知:queued=%d", queued)
|
|
}
|
|
// 第二次触发同样有界(不因重试堆积)。
|
|
c.mgr.deliverNotices(convID)
|
|
c.mgr.noticeMu.Lock()
|
|
queued = len(c.mgr.notices[convID])
|
|
c.mgr.noticeMu.Unlock()
|
|
if queued != 1 {
|
|
t.Fatalf("重复失败不应堆积通知:queued=%d", queued)
|
|
}
|
|
}
|