refactor(arch): decouple private imports, enforce contracts and comply with cordis architecture

This commit is contained in:
ryan
2026-09-03 10:40:02 +08:00
parent dbcf485d8a
commit 953a224245
107 changed files with 2028 additions and 1263 deletions
@@ -17,7 +17,6 @@ import (
"Wavelet/openflare/plugins/server/kernel/model"
analyticsmodel "Wavelet/openflare/plugins/server/kernel/model/analytics"
db "Wavelet/plugins/infra/database"
)
// cleanupTestModels 清理涉及的 5 张日志/可观测表。
@@ -42,8 +41,10 @@ func newCleanupTestDB(t *testing.T) *gorm.DB {
if err := gdb.AutoMigrate(cleanupTestModels()...); err != nil {
t.Fatalf("automigrate: %v", err)
}
db.SetDB(gdb)
t.Cleanup(func() { db.SetDB(nil) })
SetDBResolver(func(ctx context.Context) *gorm.DB {
return gdb.WithContext(ctx)
})
t.Cleanup(func() { SetDBResolver(nil) })
return gdb
}
@@ -5,7 +5,6 @@ package logstore
import (
"context"
"errors"
"fmt"
"math"
"time"
@@ -13,7 +12,6 @@ import (
"Wavelet/openflare/plugins/server/kernel/model"
analyticsmodel "Wavelet/openflare/plugins/server/kernel/model/analytics"
analyticsrepo "Wavelet/openflare/plugins/server/kernel/repository/analytics"
db "Wavelet/plugins/infra/database"
"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
)
@@ -37,11 +35,8 @@ var (
_ UserAccessLogStore = (*clickhouseUserAccessLogStore)(nil)
)
func chConnErr() error {
if db.ChConn == nil {
return errors.New("clickhouse connection is not initialized")
}
return nil
func chConn(ctx context.Context) (driver.Conn, error) {
return analyticsrepo.ChConn(ctx)
}
// ensureWritable 迁移冻结期拒绝写入。
@@ -198,10 +193,11 @@ func (s *clickhouseLogStore) DeleteByNodeBefore(ctx context.Context, nodeID stri
// ListForMigration 按 id 升序分页读取(迁移复制用):直接查询 CH 原生表。
func (s *clickhouseLogStore) ListForMigration(ctx context.Context, afterID uint64, limit int) ([]analyticsmodel.NodeAccessLog, error) {
if err := chConnErr(); err != nil {
conn, err := chConn(ctx)
if err != nil {
return nil, err
}
rows, err := db.ChConn.Query(ctx, `
rows, err := conn.Query(ctx, `
SELECT `+analyticsmodel.NodeAccessLog{}.InsertColumns()+`
FROM `+analyticsmodel.NodeAccessLog{}.TableName()+`
WHERE id > ?
@@ -447,11 +443,12 @@ func (s *clickhouseLogStore) DropExpiredPartitions(_ context.Context, _ time.Tim
// chMigrationRange 查询 CH 表时间列 MIN/MAX;空表(NULL)返回零值。
func chMigrationRange(ctx context.Context, table, column string) (time.Time, time.Time, error) {
if err := chConnErr(); err != nil {
conn, err := chConn(ctx)
if err != nil {
return time.Time{}, time.Time{}, err
}
var minTime, maxTime *time.Time
if err := db.ChConn.QueryRow(ctx,
if err := conn.QueryRow(ctx,
"SELECT min("+column+"), max("+column+") FROM "+table,
).Scan(&minTime, &maxTime); err != nil {
return time.Time{}, time.Time{}, fmt.Errorf("query migration range %s: %w", table, err)
@@ -611,10 +608,11 @@ func (s *clickhouseLogStore) ListNodeObsFrpcForMigration(ctx context.Context, af
// chListForMigration 执行按 id 升序分页的 CH 原生表查询,并交给 scanner 扫描。
func chListForMigration[T any](ctx context.Context, afterID uint64, limit int, table, columns string, scanner func(driver.Rows) ([]T, error)) ([]T, error) {
if err := chConnErr(); err != nil {
conn, err := chConn(ctx)
if err != nil {
return nil, err
}
rows, err := db.ChConn.Query(ctx, `
rows, err := conn.Query(ctx, `
SELECT `+columns+`
FROM `+table+`
WHERE id > ?
@@ -9,14 +9,15 @@ import (
"testing"
"time"
db "Wavelet/plugins/infra/database"
analyticsrepo "Wavelet/openflare/plugins/server/kernel/repository/analytics"
)
// TestClickHouseHourlyDelegationRegression 验证 CH 后端小时级聚合读委托 analyticsrepo:
// 未初始化 CH 连接时返回 analyticsrepo 的 "clickhouse connection is not initialized" 错误
// 未初始化 CH 连接时返回 analyticsrepo 的错误
// (而非未实现/panic),证明 3 个方法都路由到 CH 原生查询。
func TestClickHouseHourlyDelegationRegression(t *testing.T) {
if db.ChConn != nil {
conn, _ := analyticsrepo.ChConn(context.Background())
if conn != nil {
t.Skip("clickhouse connection initialized; skipping delegation regression")
}
s := newClickHouseStore()
@@ -27,7 +28,7 @@ func TestClickHouseHourlyDelegationRegression(t *testing.T) {
if err == nil {
t.Fatalf("%s: want clickhouse-not-initialized error, got nil", name)
}
if !strings.Contains(err.Error(), "clickhouse connection is not initialized") {
if !strings.Contains(err.Error(), "clickhouse") {
t.Fatalf("%s: unexpected error %v", name, err)
}
}
@@ -13,7 +13,8 @@ import (
"Wavelet/openflare/plugins/server/kernel/model"
"Wavelet/openflare/plugins/server/kernel/runtimeconfig"
"Wavelet/pkg/logger"
db "Wavelet/plugins/infra/database"
"gorm.io/gorm"
)
// logDatabaseKey / logMigrationKey 对应 model.ConfigKeyLogDatabase / ConfigKeyLogDBMigration。
@@ -39,6 +40,7 @@ const resolveCacheTTL = 1 * time.Second
var (
configReader ConfigReader
dbResolver func(ctx context.Context) *gorm.DB
storeMu sync.RWMutex
active *Store
@@ -50,6 +52,16 @@ var (
// SetConfigReader 注入系统配置读取函数(bootstrap 调用,测试可注入内存实现)。
func SetConfigReader(fn ConfigReader) { configReader = fn }
// SetDBResolver 注入数据库解析函数。
func SetDBResolver(fn func(ctx context.Context) *gorm.DB) { dbResolver = fn }
func getGormDB(ctx context.Context) *gorm.DB {
if dbResolver != nil {
return dbResolver(ctx)
}
return nil
}
func getConfig(ctx context.Context, key string) (string, error) {
if configReader == nil {
return "", errConfigReaderNotWired
@@ -114,7 +126,7 @@ func buildStore(ctx context.Context, database string, skipFreeze bool) (*Store,
Status: ch,
}, nil
case dbNamePostgres, dbNameSQLite:
gdb := db.DB(ctx)
gdb := getGormDB(ctx)
g := newGormStore(gdb)
g.skipFreeze = skipFreeze
ual := newUserAccessLogGormStore(gdb)