47eb23cf68
页面上的"可发起封存"原来只判 LIBRARY_AGENT_SOCKET 非空:正式栈的 API 根本没挂
那个 socket,而 agent 曾顶着正式单元名冻结候选实例——配置非空、页面可点、真发起
却封错库。
现在:agent 新增 health 动作(不占封存操作锁、不跑子进程,只回答身份/降级/忙),
worker 每 30 秒探测并写入迁移 074 的 library_executor_status;overview、快照列表与
POST /library/captures 共用同一份判定(过期、不可达、实例不符、降级、正忙都拒绝并
给原因)。封存结果由 agent 附上自报身份,worker 在停写入者之前再探测一次、执行后
用结果复核,不一致就不登记测试封存——心跳只能证明"刚才"。
期望身份用 LIBRARY_SOURCE_*(封存源),不是 LIBRARY_TARGET_*(同步目标),否则
正确的执行器会被判成不匹配。另加 GET /library/restore-availability:恢复能否执行由
双闸、该快照的恢复授权与实例维护状态决定,页面不再写死 disabled。
真跑(候选隔离栈,两处 socket 隔离不变):overview 返回 executor
{kgmaint-weknora/kgmaint-app};停 agent 后转不可达并 503 带原因;重启后恢复。
53 lines
2.0 KiB
Go
53 lines
2.0 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"time"
|
|
|
|
"knowledge-governance/internal/appconfig"
|
|
"knowledge-governance/internal/libraryexecutor"
|
|
postgresstore "knowledge-governance/internal/platform/postgres"
|
|
)
|
|
|
|
// 为什么由 worker 观测、页面读库:agent socket 只挂载在 worker 容器里,API 那个
|
|
// LIBRARY_AGENT_SOCKET 即使配了也 dial 不到。谁真能执行就由谁写下观测,
|
|
// 否则页面上的"可发起"只是配置字符串的回声。
|
|
const libraryExecutorProbeInterval = 30 * time.Second
|
|
|
|
// libraryExecutorProbeTimeout 是一次 health 往返的上限:它只是同 uid unix socket
|
|
// 上的一次 JSON 往返,慢到秒级就说明执行器有问题,不该拖住心跳。
|
|
const libraryExecutorProbeTimeout = 3 * time.Second
|
|
|
|
func recordLibraryExecutorStatus(ctx context.Context, store *postgresstore.Store, config appconfig.Config) {
|
|
// 归属用**封存源**实例:agent 冻结的是源库写入者,和同步目标(kgseal)不是一套。
|
|
instance := config.SourceInstance()
|
|
if instance == "" {
|
|
// 没有实例身份,观测就无处归属:写进去只会让页面拿别的实例的状态。
|
|
log.Print("library executor probe skipped: LIBRARY_SOURCE_INSTANCE is not configured")
|
|
return
|
|
}
|
|
observation := libraryexecutor.Probe(ctx, instance, config.LibraryAgentSocket, libraryExecutorProbeTimeout, nil)
|
|
if err := store.UpsertLibraryExecutorStatus(ctx, observation, config.WorkerID, time.Now().UTC()); err != nil {
|
|
log.Printf("library executor status not recorded: %v", err)
|
|
}
|
|
}
|
|
|
|
// runLibraryExecutorProbe 先观测一次再进循环:页面在 worker 刚起来时就该有真实状态。
|
|
func runLibraryExecutorProbe(ctx context.Context, store *postgresstore.Store, config appconfig.Config, interval time.Duration) {
|
|
if interval <= 0 {
|
|
interval = libraryExecutorProbeInterval
|
|
}
|
|
recordLibraryExecutorStatus(ctx, store, config)
|
|
ticker := time.NewTicker(interval)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
recordLibraryExecutorStatus(ctx, store, config)
|
|
}
|
|
}
|
|
}
|