Files
knowledge-governance/internal/qaopsai/run.go
T
姚章浩 9470a127f7
build / build (push) Successful in 1m11s
feat(qaops): 完成流水表六项体验与AI执行修正
统一AI分析入口及双任务安全确认,采用全量载入的可见行渲染,保留完整原文。
右侧非模态详情固定五项质量字段,清理冗余展示并对齐查询和同步按钮。
默认4并发由数据库准入与逐任务租约保护,保留共享限流冷却、截断归因和有界重试。
兼容真实引用标题字段,不伪造证据或准确率,不修改源生产问答与公司区域规则。

验证:完整make verify退出0,710项Go通过、124项已声明可选跳过且必需0跳过;
另全量mirror隔离PostgreSQL race退出0,AI单元race退出0。
真实本地浏览器通过六项交互、390px内滚动及显式AI部分失败/零缺口故障夹具。
治理原生备份已真实恢复,schema57、72表计数与29张QA内容哈希一致。
候选镜像、精确提交CI与正式上线验收待本次提交后执行,不宣称已部署。
2026-10-19 22:09:32 +08:00

71 lines
1.4 KiB
Go

package qaopsai
import (
"context"
"sync"
"time"
)
// Admission is fenced in PostgreSQL; slow model calls do not serialize source-sync or the other AI slots.
func (s *Store) Run(ctx context.Context, onError func(error)) {
if !s.valid() {
if onError != nil {
onError(ErrUnavailable)
}
return
}
var lock sync.Mutex
var lastError time.Time
report := func(err error) {
if err == nil || ctx.Err() != nil {
return
}
lock.Lock()
defer lock.Unlock()
if time.Since(lastError) > 30*time.Second {
lastError = time.Now()
if onError != nil {
onError(err)
}
}
}
var workers sync.WaitGroup
for i := 0; i < s.concurrency(); i++ {
workers.Add(1)
go func() {
defer workers.Done()
for ctx.Err() == nil {
worked, err := s.ProcessOne(ctx)
report(err)
if !worked || err != nil {
select {
case <-ctx.Done():
return
case <-time.After(time.Second):
}
}
}
}()
}
defer workers.Wait()
tick := time.NewTicker(10 * time.Second)
defer tick.Stop()
scan := func() {
scanCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
defer cancel()
_, err := s.ScanAutomatic(scanCtx)
report(err)
_, err = s.pool.Exec(scanCtx, `INSERT INTO qa_ops_ai_runtime(tenant_key,heartbeat_at)VALUES($1,clock_timestamp())ON CONFLICT(tenant_key)DO UPDATE SET heartbeat_at=EXCLUDED.heartbeat_at`, s.tenant)
report(err)
}
scan()
for {
select {
case <-ctx.Done():
return
case <-tick.C:
scan()
}
}
}