From 6fa933ac27562ef94e7f7f377ca32a033c2854ca Mon Sep 17 00:00:00 2001 From: weichen Date: Thu, 17 Sep 2026 02:04:51 +0000 Subject: [PATCH] fix(kb): return offline client instead of Fatalf under require-online Library must not abort the process; E2E callers use EnsureOnline/t.Fatal so ambient RUN_PI_E2E no longer kills short server tests. Co-authored-by: Cursor --- internal/kb/client.go | 21 +++++++++++++------ internal/server/piagent_e2e_test.go | 6 +++--- .../workflow_governance_piagent_pg_test.go | 4 ++++ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/internal/kb/client.go b/internal/kb/client.go index 7806ff2a..e500f797 100644 --- a/internal/kb/client.go +++ b/internal/kb/client.go @@ -66,9 +66,8 @@ func NewClient(cfg *config.Config) *Client { log.Printf("[kb] offline=true reason=%s detail=%v", reason, err) if envTruthy("KB_ALLOW_OFFLINE") { log.Printf("[kb] NOTE: KB offline degradation test (KB_ALLOW_OFFLINE=1)") - } - if RequireOnline() { - log.Fatalf("[kb] KB_REQUIRE_ONLINE: %v", err) + } else if RequireOnline() { + log.Printf("[kb] KB_REQUIRE_ONLINE: offline after empty password; callers must fail closed") } return c } @@ -84,9 +83,8 @@ func NewClient(cfg *config.Config) *Client { log.Printf("[kb] offline=true reason=connect_failed dsn=%s err=%v", redacted, err) if envTruthy("KB_ALLOW_OFFLINE") { log.Printf("[kb] NOTE: KB offline degradation test (KB_ALLOW_OFFLINE=1)") - } - if RequireOnline() { - log.Fatalf("[kb] KB_REQUIRE_ONLINE: cannot connect to knowledge base (%s): %v", redacted, err) + } else if RequireOnline() { + log.Printf("[kb] KB_REQUIRE_ONLINE: offline after connect failure; callers must fail closed") } return c } @@ -103,6 +101,17 @@ func (c *Client) Online() bool { return c != nil && c.pool != nil } +// EnsureOnline returns an error when RequireOnline is set and the client is offline. +func EnsureOnline(c *Client) error { + if !RequireOnline() { + return nil + } + if c == nil || !c.Online() { + return fmt.Errorf("kb: required online (KB_REQUIRE_ONLINE/RUN_PI_E2E) but client is offline; set KB_ALLOW_OFFLINE=1 only for explicit degradation tests") + } + return nil +} + // Search 通用跨领域检索 func (c *Client) Search(ctx context.Context, query string, opts SearchOptions) ([]HitItem, error) { if c.retriever == nil { diff --git a/internal/server/piagent_e2e_test.go b/internal/server/piagent_e2e_test.go index b4e3cf6f..8daadfbd 100644 --- a/internal/server/piagent_e2e_test.go +++ b/internal/server/piagent_e2e_test.go @@ -119,10 +119,10 @@ func TestPiAgent_FullLifecycle_MultiRole_RealWorld_E2E(t *testing.T) { } kbClient := kb.NewClient(cfg) defer kbClient.Close() + if err := kb.EnsureOnline(kbClient); err != nil { + t.Fatal(err) + } if !kbClient.Online() { - if kb.RequireOnline() { - t.Fatalf("KB required online but offline (host=%s port=%d); set KB_ALLOW_OFFLINE=1 only for degradation tests", cfg.KbDbHost, cfg.KbDbPort) - } t.Logf("NOTE: KB offline degradation test — continuing without shared KB") } else if stats, err := kbClient.Stats(ctx); err != nil { t.Fatalf("KB online but Stats failed: %v", err) diff --git a/internal/server/workflow_governance_piagent_pg_test.go b/internal/server/workflow_governance_piagent_pg_test.go index 6d3903b2..1a185db3 100644 --- a/internal/server/workflow_governance_piagent_pg_test.go +++ b/internal/server/workflow_governance_piagent_pg_test.go @@ -13,6 +13,7 @@ import ( "github.com/jackc/pgx/v5/pgxpool" "chat-agent-system/internal/bizdev" + "chat-agent-system/internal/kb" "chat-agent-system/internal/projectinstance" "chat-agent-system/internal/projectworkflow" "chat-agent-system/internal/server" @@ -47,6 +48,9 @@ func setupPGPiAgentServer(t *testing.T, pool *pgxpool.Pool) (http.Handler, *serv if bizdev.Snapshot(svc).Pool == nil { t.Skip("bizdev service not connected to postgres") } + if err := kb.EnsureOnline(bizdev.Snapshot(svc).KB); err != nil { + t.Fatal(err) + } srv := server.NewServer(cfg, svc) return srv.Routes(), srv }