Files
knowledge-governance/internal/monitoring/simulation.go
zheromiku dcdc8d1ddd feat: 知识治理平台(含已验证发布/回滚契约)
全栈知识治理平台首次入库(P1-P10 + 发布链路模拟验证闭环):

- 治理核心:源目录/变更集/人工审核/发布批次/发布执行(fail-closed 闸口)
- 测试通道:WeKnora 测试 KB 上传/轮询/验收;poll 完成时写入
  parser_generation/index_generation,修复 manual/seed 路径发布闸口永久拦截
- 发布适配器 v071(本地 source=测试角色 / 云端 target=生产角色 模拟验证通过):
  * ES 导出/导入 mapping 自适应(.keyword 子字段、可选 tenant_id)
  * OSS locator 支持嵌套 scheme;chunks.seq_id 由目标序列分配
  * bundle 归档同身份重试原子替换;verifier 按 bundle chunk_type 计数
  * 回滚 job payload 支持 prior_execution_id(strict 解码)
- 三通道发布+回滚演练实测:publish 4/4 verified,检索命中,
  rollback 4/4 rolled_back,目标端 PG is_enabled=false、ES is_enabled=false
- 前端 A·Data-console 风格全站统一,120 用例通过
- 门禁:go vet / go test 全包通过,gofmt 干净
2026-09-30 10:54:06 +08:00

88 lines
5.0 KiB
Go

package monitoring
import (
"context"
"errors"
"time"
"knowledge-governance/internal/governance"
)
type SimulationProvider struct{ now func() time.Time }
func NewSimulationProvider(now func() time.Time) *SimulationProvider {
if now == nil {
now = time.Now
}
return &SimulationProvider{now: now}
}
func (provider *SimulationProvider) Overview(context.Context) (governance.MonitorOverview, error) {
now := provider.now().UTC()
return governance.MonitorOverview{
Mode: "simulation", Simulated: true, ObservedAt: now,
Host: governance.MonitorHost{CPUPercent: 42, MemoryUsedBytes: 19971597926, MemoryTotalBytes: 34359738368, DiskUsedBytes: 128849018880, DiskTotalBytes: 536870912000, GPUState: "unknown", GPUDetail: "未接入真实GPU监控", Simulated: true},
Services: []governance.MonitorService{
{Key: "weknora", Name: "WeKnora API", State: "healthy", Detail: "模拟连接正常", LatencyMS: 86, ObservedAt: now, Simulated: true},
{Key: "embedding", Name: "Embedding模型", State: "healthy", Detail: "模拟探测通过", LatencyMS: 142, ObservedAt: now, Simulated: true},
{Key: "llm", Name: "LLM模型", State: "healthy", Detail: "模拟探测通过", LatencyMS: 318, ObservedAt: now, Simulated: true},
{Key: "mineru", Name: "MinerU", State: "healthy", Detail: "模拟处理中2,队列5", LatencyMS: 24, ObservedAt: now, Simulated: true},
{Key: "postgres", Name: "PostgreSQL", State: "unknown", Detail: "未接入真实监控", ObservedAt: now, Simulated: true},
{Key: "redis", Name: "Redis / MQ", State: "unknown", Detail: "未接入真实监控", ObservedAt: now, Simulated: true},
{Key: "oss", Name: "OSS", State: "unknown", Detail: "未接入真实监控", ObservedAt: now, Simulated: true},
},
KnowledgeBases: []governance.KnowledgeBaseProgress{{ID: "simulation-company-support", Name: "公司级技术支持知识库", Visibility: "mixed", Imported: 5750, Completed: 4530, Pending: 450, Processing: 50, Finalizing: 714, Failed: 6, InternalImported: 4200, InternalCompleted: 3300, ExternalImported: 1550, ExternalCompleted: 1230}},
}, nil
}
var simulationFiles = []governance.KnowledgeMonitorFile{
{Name: "[模拟] CR5用户手册.pdf", Directory: "02|产品资料/CR系列", Visibility: "internal", Status: "completed", StageDetail: "解析、切片和增强任务均完成", ElapsedSecond: 0},
{Name: "[模拟] MG400部署说明.pdf", Directory: "03|机器人部署与使用", Visibility: "internal", Status: "pending", StageDetail: "等待进入解析队列", ElapsedSecond: 420},
{Name: "[模拟] 产品参数总表.xlsx", Directory: "02|产品资料", Visibility: "external", Status: "finalizing", StageDetail: "基础检索可用,Wiki与图谱仍在生成", ElapsedSecond: 2100},
{Name: "[模拟] 二次开发接口说明.docx", Directory: "05|二次开发", Visibility: "internal", Status: "processing", StageDetail: "正在切片和向量化", ElapsedSecond: 480},
{Name: "[模拟] CRA-IP68产品介绍.pdf", Directory: "06|应用案例与解决方案", Visibility: "external", Status: "failed", StageDetail: "MinerU解析失败", ElapsedSecond: 720, ErrorCode: "mineru_parse_failed"},
}
func (provider *SimulationProvider) ListFiles(_ context.Context, knowledgeBaseID, status string, limit, offset int) (governance.KnowledgeMonitorFilePage, error) {
if knowledgeBaseID != "simulation-company-support" || limit < 1 || limit > 100 || offset < 0 {
return governance.KnowledgeMonitorFilePage{}, errors.New("invalid monitor file query")
}
allowed := map[string]bool{"": true, "completed": true, "pending": true, "processing": true, "finalizing": true, "failed": true, "cancelled": true}
if !allowed[status] {
return governance.KnowledgeMonitorFilePage{}, errors.New("invalid monitor status")
}
filtered := make([]governance.KnowledgeMonitorFile, 0)
for _, item := range simulationFiles {
if status == "" || item.Status == status {
filtered = append(filtered, item)
}
}
page := governance.KnowledgeMonitorFilePage{Total: len(filtered), Limit: limit, Offset: offset, SampleOnly: true, Items: []governance.KnowledgeMonitorFile{}}
if offset < len(filtered) {
end := offset + limit
if end > len(filtered) {
end = len(filtered)
}
page.Items = append(page.Items, filtered[offset:end]...)
}
return page, nil
}
// Metrics declares that no real run metrics exist in simulation mode: every
// sample-dependent number stays null instead of pretending to be zero (P9).
func (provider *SimulationProvider) Metrics(context.Context) (governance.RunMetrics, error) {
now := provider.now().UTC()
return governance.RunMetrics{
ObservedAt: now,
WorkerSource: "simulation",
ShortWindow: governance.JobWindowMetrics{WindowSeconds: int((1 * time.Hour).Seconds())},
LongWindow: governance.JobWindowMetrics{WindowSeconds: int((24 * time.Hour).Seconds())},
}, nil
}
// Services declares that a simulation provider owns no real dependencies: every
// readiness judgement belongs to the real provider.
func (provider *SimulationProvider) Services(_ context.Context) []governance.ServiceHealth {
return []governance.ServiceHealth{}
}