package postgres import ( "context" "encoding/json" "errors" "fmt" "time" "github.com/jackc/pgx/v5" "knowledge-governance/internal/libraryexecutor" ) // 为什么落库而不是 API 直接探测:agent socket 只挂在 worker 容器里,API 那个 // LIBRARY_AGENT_SOCKET 即使配了也 dial 不到。谁真能执行就由谁观测,页面读结果。 const executorStatusColumns = `instance, reachable, busy, degraded, identity, status_error, observed_at` // UpsertLibraryExecutorStatus 记录一次真实探测。降级/不可达同样要写: // "最新一次观测是什么"比"最后一条好消息"更有用。 func (s *Store) UpsertLibraryExecutorStatus(ctx context.Context, observation libraryexecutor.Observation, observer string, now time.Time) error { identity, err := json.Marshal(observation.Identity) if err != nil { return fmt.Errorf("encode library executor identity: %w", err) } if observation.Instance == "" { return errors.New("library executor observation needs an instance") } observedAt := observation.ObservedAt if observedAt.IsZero() { observedAt = now } _, err = s.db.Exec(ctx, ` INSERT INTO library_executor_status (instance, reachable, busy, degraded, identity, status_error, observer, observed_at) VALUES ($1,$2,$3,$4,$5::jsonb,$6,$7,$8) ON CONFLICT (instance) DO UPDATE SET reachable = EXCLUDED.reachable, busy = EXCLUDED.busy, degraded = EXCLUDED.degraded, identity = EXCLUDED.identity, status_error = EXCLUDED.status_error, observer = EXCLUDED.observer, observed_at = EXCLUDED.observed_at`, observation.Instance, observation.Reachable, observation.Busy, observation.Degraded, string(identity), observation.Error, observer, observedAt.UTC()) if err != nil { return fmt.Errorf("record library executor status: %w", err) } return nil } // LibraryExecutorStatus 读某个实例最近一次观测;没有记录返回 nil(不是"可用")。 func (s *Store) LibraryExecutorStatus(ctx context.Context, instance string) (*libraryexecutor.Observation, error) { row := s.db.QueryRow(ctx, `SELECT `+executorStatusColumns+` FROM library_executor_status WHERE instance=$1`, instance) var observation libraryexecutor.Observation var raw []byte err := row.Scan(&observation.Instance, &observation.Reachable, &observation.Busy, &observation.Degraded, &raw, &observation.Error, &observation.ObservedAt) if errors.Is(err, pgx.ErrNoRows) { return nil, nil } if err != nil { return nil, fmt.Errorf("read library executor status: %w", err) } if len(raw) > 0 { if err := json.Unmarshal(raw, &observation.Identity); err != nil { return nil, fmt.Errorf("library executor identity unreadable: %w", err) } } return &observation, nil }