优化
This commit is contained in:
+46
-25
@@ -3,7 +3,7 @@ package data
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -16,24 +16,33 @@ import (
|
||||
var ProviderSet = wire.NewSet(NewData, NewRuntimeSettings, NewTokenIssuer, NewUserRepo, NewInitializationRepo, NewAuthorityAccessRepo, NewAPIRepo, NewPermissionRepo, NewMenuRepo, NewDepartmentRepo, NewPositionRepo, NewDictionaryRepo, NewParameterRepo, NewAPITokenRepo, NewSecurityRepo, NewVersionRepo, NewExportRepo, NewAuditRepo, NewAuditRecorderRepo, NewLogFileRepo, NewTaskRepo, NewMediaRepo, NewAnnouncementRepo, NewEmailRepo, NewCache, NewFileStorage)
|
||||
|
||||
type Data struct {
|
||||
initMu sync.Mutex
|
||||
configMu sync.Mutex
|
||||
gormDB *reloadableDB
|
||||
redis *reloadableRedis
|
||||
mongo *reloadableMongo
|
||||
runtime *conf.Runtime
|
||||
storage *reloadableStorage
|
||||
dbListMu sync.RWMutex
|
||||
dbList map[string]*gorm.DB
|
||||
initMu sync.Mutex
|
||||
configMu sync.Mutex
|
||||
gormDB *reloadableDB
|
||||
redis *reloadableRedis
|
||||
mongo *reloadableMongo
|
||||
runtime *conf.Runtime
|
||||
storage *reloadableStorage
|
||||
dbListMu sync.RWMutex
|
||||
dbList map[string]*gorm.DB
|
||||
appLogger *slog.Logger
|
||||
auditLog *dataScopeAuditWriter
|
||||
}
|
||||
|
||||
func openDatabaseList(configs []*conf.Data_Database) (map[string]*gorm.DB, error) {
|
||||
func (d *Data) logger() *slog.Logger {
|
||||
if d != nil && d.appLogger != nil {
|
||||
return d.appLogger
|
||||
}
|
||||
return slog.Default()
|
||||
}
|
||||
|
||||
func openDatabaseList(configs []*conf.Data_Database, appLogger ...*slog.Logger) (map[string]*gorm.DB, error) {
|
||||
items := make(map[string]*gorm.DB)
|
||||
for _, config := range configs {
|
||||
if config == nil || config.Disable || config.AliasName == "" {
|
||||
continue
|
||||
}
|
||||
db, err := openDatabase(config, false, "")
|
||||
db, err := openDatabase(config, false, "", appLogger...)
|
||||
if err != nil {
|
||||
for _, opened := range items {
|
||||
if sqlDB, dbErr := opened.DB(); dbErr == nil {
|
||||
@@ -42,7 +51,6 @@ func openDatabaseList(configs []*conf.Data_Database) (map[string]*gorm.DB, error
|
||||
}
|
||||
return nil, fmt.Errorf("open database %q: %w", config.AliasName, err)
|
||||
}
|
||||
registerDataScopeCallbacks(db)
|
||||
items[config.AliasName] = db
|
||||
}
|
||||
return items, nil
|
||||
@@ -77,30 +85,38 @@ func (d *Data) database(name string) (*gorm.DB, error) {
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func NewData(runtime *conf.Runtime) (*Data, func(), error) {
|
||||
func NewData(runtime *conf.Runtime, appLogger *slog.Logger) (*Data, func(), error) {
|
||||
if appLogger == nil {
|
||||
appLogger = slog.Default()
|
||||
}
|
||||
c := runtime.Data()
|
||||
if c == nil || c.Database == nil {
|
||||
return nil, nil, fmt.Errorf("database configuration is required")
|
||||
}
|
||||
d := &Data{runtime: runtime}
|
||||
db, err := openDatabase(c.Database, false, "")
|
||||
d := &Data{runtime: runtime, appLogger: appLogger}
|
||||
db, err := openDatabase(c.Database, false, "", appLogger)
|
||||
usingFallback := false
|
||||
if err != nil {
|
||||
// The initialization endpoint must remain available when the configured
|
||||
// target database has not been created yet.
|
||||
log.Printf("configured database unavailable before initialization: %v", err)
|
||||
db, err = openFallbackDatabase()
|
||||
appLogger.Warn("configured database unavailable before initialization", "mod", "system", "error", err)
|
||||
db, err = openFallbackDatabase(appLogger)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("open bootstrap database: %w", err)
|
||||
}
|
||||
usingFallback = true
|
||||
}
|
||||
d.gormDB = newReloadableDB(db)
|
||||
d.dbList, err = openDatabaseList(c.DatabaseList)
|
||||
d.gormDB = newReloadableDB(db, d.enqueueDataScopeAudit)
|
||||
d.auditLog = newDataScopeAuditWriter(d, appLogger)
|
||||
d.dbList, err = openDatabaseList(c.DatabaseList, appLogger)
|
||||
if err != nil {
|
||||
d.auditLog.Close()
|
||||
d.gormDB.close()
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, item := range d.dbList {
|
||||
registerDataScopeCallbacks(item, d.enqueueDataScopeAudit)
|
||||
}
|
||||
admin := runtime.Admin()
|
||||
disableAutoMigrate := admin != nil && admin.System != nil && admin.System.DisableAutoMigrate
|
||||
if !usingFallback && !disableAutoMigrate {
|
||||
@@ -109,17 +125,18 @@ func NewData(runtime *conf.Runtime) (*Data, func(), error) {
|
||||
}
|
||||
}
|
||||
useRedis := admin != nil && admin.System != nil && admin.System.UseRedis
|
||||
d.redis = newReloadableRedis(openRedis(c.Redis, useRedis))
|
||||
d.redis = newReloadableRedis(openRedis(c.Redis, useRedis, appLogger))
|
||||
useMongo := admin != nil && admin.System != nil && admin.System.UseMongo
|
||||
mongoClient, err := openMongo(c.Mongo, useMongo)
|
||||
if err != nil {
|
||||
log.Printf("mongo unavailable: %v", err)
|
||||
appLogger.Error("mongo unavailable", "mod", "mongo", "error", err)
|
||||
mongoClient = nil
|
||||
}
|
||||
d.mongo = newReloadableMongo(mongoClient)
|
||||
stopConfigWatcher := d.watchConfig()
|
||||
cleanup := func() {
|
||||
stopConfigWatcher()
|
||||
d.auditLog.Close()
|
||||
d.gormDB.close()
|
||||
closeDatabaseList(d.dbList)
|
||||
d.redis.close()
|
||||
@@ -128,7 +145,7 @@ func NewData(runtime *conf.Runtime) (*Data, func(), error) {
|
||||
return d, cleanup, nil
|
||||
}
|
||||
|
||||
func openRedis(config *conf.Data_Redis, enabled bool) redis.UniversalClient {
|
||||
func openRedis(config *conf.Data_Redis, enabled bool, appLogger ...*slog.Logger) redis.UniversalClient {
|
||||
if !enabled || config == nil || (config.Addr == "" && len(config.ClusterAddrs) == 0) {
|
||||
return nil
|
||||
}
|
||||
@@ -152,7 +169,11 @@ func openRedis(config *conf.Data_Redis, enabled bool) redis.UniversalClient {
|
||||
pingCtx, cancel := context.WithTimeout(context.Background(), 800*time.Millisecond)
|
||||
defer cancel()
|
||||
if err := candidate.Ping(pingCtx).Err(); err != nil {
|
||||
log.Printf("redis unavailable, using in-memory cache: %v", err)
|
||||
log := slog.Default()
|
||||
if len(appLogger) > 0 && appLogger[0] != nil {
|
||||
log = appLogger[0]
|
||||
}
|
||||
log.Warn("redis unavailable, using in-memory cache", "mod", "redis", "error", err)
|
||||
_ = candidate.Close()
|
||||
return nil
|
||||
}
|
||||
@@ -160,6 +181,6 @@ func openRedis(config *conf.Data_Redis, enabled bool) redis.UniversalClient {
|
||||
}
|
||||
|
||||
func (d *Data) activateDatabase(db *gorm.DB, config *conf.Data_Database) {
|
||||
d.gormDB.replace(db)
|
||||
d.gormDB.replace(db, d.enqueueDataScopeAudit)
|
||||
d.runtime.UpdateDatabase(config)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user