From 6461033a835baa405f777c63a298abb716939a2c Mon Sep 17 00:00:00 2001 From: engigu Date: Tue, 24 Mar 2026 09:03:27 +0800 Subject: [PATCH] chore: speedup bootstrap and migrate --- docker/docker-entrypoint.sh | 1 - internal/bootstrap/bootstrap.go | 11 ++++ internal/database/migrate.go | 94 +++++++++++++++++++++++++------ internal/services/migration_v3.go | 1 + 4 files changed, 90 insertions(+), 17 deletions(-) diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index 2e739ef..078df90 100644 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -74,7 +74,6 @@ log " - python: $(python --version 2>&1 | head -n 1 || echo "not found")" log "Checking node..." log " - node: $(node --version 2>&1 | head -n 1 || echo "not found")" -# 延迟获取 NODE_PATH,避免同步阻塞启动 log "Checking npm..." log " - npm: $(npm --version 2>&1 | head -n 1 || echo "not found")" diff --git a/internal/bootstrap/bootstrap.go b/internal/bootstrap/bootstrap.go index 3b7b18d..8b45f80 100644 --- a/internal/bootstrap/bootstrap.go +++ b/internal/bootstrap/bootstrap.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "runtime" + "time" "github.com/engigu/baihu-panel/internal/constant" "github.com/engigu/baihu-panel/internal/database" @@ -94,14 +95,24 @@ func (a *App) initDatabase() { logger.Fatalf("Failed to init database: %v", err) } + // 记录各个初始化阶段的时间 + startTime := time.Now() + // 执行 V3 迁移(ID 变更迁移) if err := services.RunMigrationV3(); err != nil { logger.Fatalf("Failed to run V3 migration: %v", err) } + v3Duration := time.Since(startTime) + logger.Infof("[Database] V3 迁移检查完成, 耗时: %v", v3Duration) + // 执行表结构同步 + migrateStart := time.Now() if err := database.Migrate(); err != nil { logger.Fatalf("Failed to migrate database: %v", err) } + migrateDuration := time.Since(migrateStart) + logger.Infof("[Database] 表结构同步完成, 耗时: %v", migrateDuration) + logger.Infof("[Database] 数据库总初始化耗时: %v", time.Since(startTime)) } func (a *App) initRouter() { diff --git a/internal/database/migrate.go b/internal/database/migrate.go index 0ca58ff..be5144f 100644 --- a/internal/database/migrate.go +++ b/internal/database/migrate.go @@ -1,36 +1,98 @@ package database import ( + "crypto/md5" + "encoding/hex" + "reflect" "strings" + "github.com/engigu/baihu-panel/internal/constant" "github.com/engigu/baihu-panel/internal/logger" "github.com/engigu/baihu-panel/internal/models" ) +var allModels = []interface{}{ + &models.AppLog{}, + &models.User{}, + &models.Task{}, + &models.TaskLog{}, + &models.Script{}, + &models.EnvironmentVariable{}, + &models.Setting{}, + &models.SendStats{}, + &models.Dependency{}, + &models.Agent{}, + &models.AgentToken{}, + &models.Language{}, + &models.NotifyWay{}, + &models.NotifyBinding{}, +} + func Migrate() error { + // 1. 自动指纹识别,大幅提升远程数据库启动进度 + sig := getModelSignature(allModels) + if DB.Migrator().HasTable(&models.Setting{}) { + var sigSetting models.Setting + res := DB.Where("section = ? AND `key` = ?", "system", "schema_signature").Limit(1).Find(&sigSetting) + if res.RowsAffected > 0 && string(sigSetting.Value) == sig { + logger.Info("[Database] 模型指纹一致,跳过自动表结构同步") + return nil + } + } + // 执行自定义迁移 + logger.Info("[Database] 正在执行自定义迁移与表结构同步...") if err := customMigrations(); err != nil { logger.Warnf("[Database] 自定义迁移警告: %v", err) } - allModels := []interface{}{ - &models.AppLog{}, - &models.User{}, - &models.Task{}, - &models.TaskLog{}, - &models.Script{}, - &models.EnvironmentVariable{}, - &models.Setting{}, - &models.SendStats{}, - &models.Dependency{}, - &models.Agent{}, - &models.AgentToken{}, - &models.Language{}, - &models.NotifyWay{}, - &models.NotifyBinding{}, + logger.Infof("[Database] 正在同步 %d 个数据模型的表结构...", len(allModels)) + if err := AutoMigrate(allModels...); err != nil { + return err } - return AutoMigrate(allModels...) + // 3. 更新指纹记录 + if DB.Migrator().HasTable(&models.Setting{}) { + var sigSetting models.Setting + res := DB.Where("section = ? AND `key` = ?", "system", "schema_signature").Limit(1).Find(&sigSetting) + if res.RowsAffected > 0 { + DB.Model(&sigSetting).Update("value", models.BigText(sig)) + } else { + DB.Create(&models.Setting{ + ID: "sys_schema_sig", + Section: "system", + Key: "schema_signature", + Value: models.BigText(sig), + }) + } + } + + return nil +} + +// getModelSignature 生成数据模型的结构指纹 +func getModelSignature(models []interface{}) string { + var sb strings.Builder + // 包含表前缀,确保前缀变更时也能触发迁移 + sb.WriteString(constant.TablePrefix) + for _, m := range models { + t := reflect.TypeOf(m) + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + sb.WriteString(t.Name()) + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + if f.Anonymous { + continue + } + sb.WriteString(f.Name) + sb.WriteString(f.Type.String()) + sb.WriteString(f.Tag.Get("gorm")) + } + } + hash := md5.Sum([]byte(sb.String())) + return hex.EncodeToString(hash[:]) } // hasGormTypeText 检查 gorm tag 中是否包含 type:text diff --git a/internal/services/migration_v3.go b/internal/services/migration_v3.go index 8680ff6..e2a38ec 100644 --- a/internal/services/migration_v3.go +++ b/internal/services/migration_v3.go @@ -84,6 +84,7 @@ func RunMigrationV3() error { res := db.Where("section = ? AND `key` = ?", "system", "migration_v3_success").Limit(1).Find(&migrationFlag) if res.Error == nil && res.RowsAffected > 0 && migrationFlag.Value == "true" { // 如果已经是字符串 ID 模式,双重确认 + logger.Info("[MigrationV3] 系统已处于 V3 模式,跳过检查") return nil } }