fix(models): isolate versioned migration sessions

This commit is contained in:
2026-07-22 14:45:41 +08:00
parent 78d4845688
commit 217f82c57c
2 changed files with 12 additions and 5 deletions

View File

@@ -33,14 +33,18 @@ func runVersionedMigrations(database *gorm.DB) error {
{version: 2, name: "deduplicate_project_tags", run: deduplicateLegacyProjectTags}, {version: 2, name: "deduplicate_project_tags", run: deduplicateLegacyProjectTags},
} }
for _, migration := range migrations { for _, migration := range migrations {
// Connection callbacks can provide an initialized Gorm session. Start each
// migration from a clean statement so Model/Where clauses used to check the
// version table are not inherited by the data-repair transaction.
migrationDatabase := database.Session(&gorm.Session{NewDB: true})
var applied int64 var applied int64
if err := database.Model(&SenlinAgentSchemaMigration{}).Where("version = ?", migration.version).Count(&applied).Error; err != nil { if err := migrationDatabase.Model(&SenlinAgentSchemaMigration{}).Where("version = ?", migration.version).Count(&applied).Error; err != nil {
return err return err
} }
if applied > 0 { if applied > 0 {
continue continue
} }
if err := database.Transaction(func(tx *gorm.DB) error { if err := migrationDatabase.Session(&gorm.Session{NewDB: true}).Transaction(func(tx *gorm.DB) error {
details, err := migration.run(tx) details, err := migration.run(tx)
if err != nil { if err != nil {
return err return err
@@ -61,7 +65,7 @@ func runVersionedMigrations(database *gorm.DB) error {
func normalizeLegacyProjectIdentifiers(tx *gorm.DB) (map[string]int, error) { func normalizeLegacyProjectIdentifiers(tx *gorm.DB) (map[string]int, error) {
var projects []SenlinAgentProject var projects []SenlinAgentProject
if err := tx.Select("id", "owner_id", "identifier").Order("owner_id asc, id asc").Find(&projects).Error; err != nil { if err := tx.Model(&SenlinAgentProject{}).Select("id", "owner_id", "identifier").Order("owner_id asc, id asc").Find(&projects).Error; err != nil {
return nil, err return nil, err
} }
@@ -121,7 +125,7 @@ func uniqueIdentifier(base string, reserved map[string]struct{}) string {
func deduplicateLegacyProjectTags(tx *gorm.DB) (map[string]int, error) { func deduplicateLegacyProjectTags(tx *gorm.DB) (map[string]int, error) {
var tags []SenlinAgentTag var tags []SenlinAgentTag
if err := tx.Select("id", "identity", "project_id", "name").Order("project_id asc, name asc, id asc").Find(&tags).Error; err != nil { if err := tx.Model(&SenlinAgentTag{}).Select("id", "identity", "project_id", "name").Order("project_id asc, name asc, id asc").Find(&tags).Error; err != nil {
return nil, err return nil, err
} }
keepers := make(map[string]SenlinAgentTag) keepers := make(map[string]SenlinAgentTag)

View File

@@ -35,7 +35,10 @@ func TestAutoMigrateUpgradesLegacyProjectsAndTagsWithoutLosingAssociations(t *te
require.NoError(t, database.Exec(statement).Error) require.NoError(t, database.Exec(statement).Error)
} }
require.NoError(t, AutoMigrate(database)) // PostgreSQL migrations run through database.Connection, whose callback DB can
// carry an initialized Gorm statement. Exercise that mode so model state from
// the migration-version lookup cannot leak into the data-repair transaction.
require.NoError(t, AutoMigrate(database.Session(&gorm.Session{Initialized: true})))
var projects []SenlinAgentProject var projects []SenlinAgentProject
require.NoError(t, database.Order("id asc").Find(&projects).Error) require.NoError(t, database.Order("id asc").Find(&projects).Error)