优化结构
This commit is contained in:
+120
-5
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/google/wire"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"gorm.io/gorm"
|
||||
"kra/internal/config"
|
||||
dataintegration "kra/internal/data/integration"
|
||||
@@ -45,9 +46,12 @@ func NewIntegrationRuntime(data *Data) *runtimeconfig.Store {
|
||||
type Data struct {
|
||||
initMu sync.Mutex
|
||||
configMu sync.Mutex
|
||||
resourceMu sync.RWMutex
|
||||
databaseReady atomic.Bool
|
||||
gormDB *reloadableDB
|
||||
redis *reloadableRedis
|
||||
redisListMu sync.RWMutex
|
||||
redisList map[string]redis.UniversalClient
|
||||
mongo *reloadableMongo
|
||||
runtime *config.Store
|
||||
integrations *runtimeconfig.Store
|
||||
@@ -57,6 +61,7 @@ type Data struct {
|
||||
appLogger *slog.Logger
|
||||
auditLog *dataScopeAuditWriter
|
||||
catalog module.Catalog
|
||||
resourceHook func()
|
||||
}
|
||||
|
||||
// DB exposes the active primary database to narrowly scoped data submodules.
|
||||
@@ -105,6 +110,79 @@ func (d *Data) RedisClient() redis.UniversalClient {
|
||||
return d.redis.load()
|
||||
}
|
||||
|
||||
// MongoClient returns the currently active Mongo client. The client remains
|
||||
// owned by Data and is only exposed here for framework-level resource wiring.
|
||||
func (d *Data) MongoClient() *mongo.Client {
|
||||
if d == nil || d.mongo == nil {
|
||||
return nil
|
||||
}
|
||||
return d.mongo.load()
|
||||
}
|
||||
|
||||
// NamedDatabases returns a copy of configured secondary database handles for
|
||||
// the process-wide resource registry. Data retains lifecycle ownership.
|
||||
func (d *Data) NamedDatabases() map[string]*gorm.DB {
|
||||
if d == nil {
|
||||
return nil
|
||||
}
|
||||
d.dbListMu.RLock()
|
||||
defer d.dbListMu.RUnlock()
|
||||
if len(d.dbList) == 0 {
|
||||
return nil
|
||||
}
|
||||
result := make(map[string]*gorm.DB, len(d.dbList))
|
||||
for name, db := range d.dbList {
|
||||
if name != "" && db != nil {
|
||||
result[name] = db
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// NamedRedisClients returns a copy of configured secondary Redis handles for
|
||||
// the process-wide resource registry. Data retains lifecycle ownership.
|
||||
func (d *Data) NamedRedisClients() map[string]redis.UniversalClient {
|
||||
if d == nil {
|
||||
return nil
|
||||
}
|
||||
d.redisListMu.RLock()
|
||||
defer d.redisListMu.RUnlock()
|
||||
if len(d.redisList) == 0 {
|
||||
return nil
|
||||
}
|
||||
result := make(map[string]redis.UniversalClient, len(d.redisList))
|
||||
for name, client := range d.redisList {
|
||||
if name != "" && client != nil {
|
||||
result[name] = client
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// SetResourceHook registers a composition-root callback invoked after active
|
||||
// database, Redis, or Mongo handles change. A callback keeps data independent
|
||||
// from the global package while allowing the root to refresh shared handles.
|
||||
func (d *Data) SetResourceHook(hook func()) {
|
||||
if d == nil {
|
||||
return
|
||||
}
|
||||
d.resourceMu.Lock()
|
||||
d.resourceHook = hook
|
||||
d.resourceMu.Unlock()
|
||||
}
|
||||
|
||||
func (d *Data) notifyResources() {
|
||||
if d == nil {
|
||||
return
|
||||
}
|
||||
d.resourceMu.RLock()
|
||||
hook := d.resourceHook
|
||||
d.resourceMu.RUnlock()
|
||||
if hook != nil {
|
||||
hook()
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Data) logger() *slog.Logger {
|
||||
if d != nil && d.appLogger != nil {
|
||||
return d.appLogger
|
||||
@@ -176,13 +254,9 @@ func NewData(runtime *config.Store, appLogger *slog.Logger, storageManager *stor
|
||||
c.Database = &config.Database{}
|
||||
}
|
||||
d := &Data{runtime: runtime, integrations: runtimeconfig.NewStore(), appLogger: appLogger, storage: storageManager, catalog: catalog}
|
||||
var stopConfigWatcher func()
|
||||
var cleanupOnce sync.Once
|
||||
cleanup := func() {
|
||||
cleanupOnce.Do(func() {
|
||||
if stopConfigWatcher != nil {
|
||||
stopConfigWatcher()
|
||||
}
|
||||
if d.auditLog != nil {
|
||||
d.auditLog.Close()
|
||||
}
|
||||
@@ -193,6 +267,7 @@ func NewData(runtime *config.Store, appLogger *slog.Logger, storageManager *stor
|
||||
if d.redis != nil {
|
||||
d.redis.close()
|
||||
}
|
||||
closeRedisList(d.redisList)
|
||||
if d.mongo != nil {
|
||||
d.mongo.close()
|
||||
}
|
||||
@@ -275,6 +350,8 @@ func NewData(runtime *config.Store, appLogger *slog.Logger, storageManager *stor
|
||||
}
|
||||
useRedis := admin != nil && admin.System != nil && admin.System.UseRedis
|
||||
d.redis = newReloadableRedis(openRedis(c.Redis, useRedis, appLogger))
|
||||
useRedisList := useRedis && admin.System.UseMultipoint
|
||||
d.redisList = openRedisList(c.RedisList, useRedisList, appLogger)
|
||||
useMongo := admin != nil && admin.System != nil && admin.System.UseMongo
|
||||
mongoClient, err := openMongo(c.Mongo, useMongo)
|
||||
if err != nil {
|
||||
@@ -282,7 +359,6 @@ func NewData(runtime *config.Store, appLogger *slog.Logger, storageManager *stor
|
||||
mongoClient = nil
|
||||
}
|
||||
d.mongo = newReloadableMongo(mongoClient)
|
||||
stopConfigWatcher = d.watchConfig()
|
||||
initialized = true
|
||||
return d, cleanup, nil
|
||||
}
|
||||
@@ -322,8 +398,47 @@ func openRedis(config *config.Redis, enabled bool, appLogger ...*slog.Logger) re
|
||||
return candidate
|
||||
}
|
||||
|
||||
func openRedisList(configs []*config.Redis, enabled bool, appLogger ...*slog.Logger) map[string]redis.UniversalClient {
|
||||
if !enabled || len(configs) == 0 {
|
||||
return nil
|
||||
}
|
||||
clients := make(map[string]redis.UniversalClient)
|
||||
for _, item := range configs {
|
||||
if item == nil || item.Name == "" {
|
||||
continue
|
||||
}
|
||||
if client := openRedis(item, true, appLogger...); client != nil {
|
||||
clients[item.Name] = client
|
||||
}
|
||||
}
|
||||
if len(clients) == 0 {
|
||||
return nil
|
||||
}
|
||||
return clients
|
||||
}
|
||||
|
||||
func closeRedisList(clients map[string]redis.UniversalClient) {
|
||||
for _, client := range clients {
|
||||
if client != nil {
|
||||
_ = client.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Data) replaceRedisList(clients map[string]redis.UniversalClient) {
|
||||
if d == nil {
|
||||
return
|
||||
}
|
||||
d.redisListMu.Lock()
|
||||
old := d.redisList
|
||||
d.redisList = clients
|
||||
d.redisListMu.Unlock()
|
||||
closeRedisList(old)
|
||||
}
|
||||
|
||||
func (d *Data) activateDatabase(db *gorm.DB, config *config.Database) {
|
||||
d.gormDB.replace(db, d.enqueueDataScopeAudit)
|
||||
d.runtime.UpdateDatabase(config)
|
||||
d.databaseReady.Store(true)
|
||||
d.notifyResources()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user