From 5826b98b950b325dca5d6904cb30506ad51dc2ff Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Sat, 6 Jan 2024 19:26:18 +0800 Subject: [PATCH] fix: migrate is a separate command --- internal/app/server/server.go | 3 +- internal/repo/db/pg.go | 84 ++++++++++++++++------------------- 2 files changed, 41 insertions(+), 46 deletions(-) diff --git a/internal/app/server/server.go b/internal/app/server/server.go index c54f182..3088359 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -8,6 +8,7 @@ import ( "git.0x7f.app/WOJ/woj-server/internal/misc/config" "git.0x7f.app/WOJ/woj-server/internal/misc/log" "git.0x7f.app/WOJ/woj-server/internal/model" + "git.0x7f.app/WOJ/woj-server/internal/repo/db" "git.0x7f.app/WOJ/woj-server/internal/web/router" "git.0x7f.app/WOJ/woj-server/pkg/utils" "git.0x7f.app/WOJ/woj-server/pkg/zapasynq" @@ -23,7 +24,7 @@ import ( ) func RunServerMigrate(i *do.Injector) error { - + do.MustInvoke[db.Service](i).Migrate() return nil } diff --git a/internal/repo/db/pg.go b/internal/repo/db/pg.go index 77aba43..ae068e2 100644 --- a/internal/repo/db/pg.go +++ b/internal/repo/db/pg.go @@ -22,7 +22,7 @@ var _ Service = (*service)(nil) type Service interface { Get() *gorm.DB - Close() error + Migrate() HealthCheck() error Shutdown() error } @@ -46,7 +46,44 @@ func (s *service) Get() *gorm.DB { return s.db } -func (s *service) Close() error { +func (s *service) Migrate() { + s.log.Info("Auto Migrating database...") + + // Running AutoMigrate concurrently on the same model fails with various race conditions + // https://github.com/go-gorm/gorm/pull/6680 + // https://github.com/go-gorm/postgres/pull/224 + + // Obtain a lock to prevent concurrent AutoMigrate + + lockID := func(s string) int64 { + h := fnv.New64a() + _, err := h.Write([]byte(s)) + return utils.If(err != nil, int64(0x4242AA55), int64(h.Sum64())) + }("gorm:migrator") + + s.err = s.db.Exec("SELECT pg_advisory_lock(?)", lockID).Error + if s.err != nil { + s.log.Error("Failed to obtain lock", zap.Error(s.err)) + return + } + + _ = s.db.AutoMigrate(&model.User{}) + _ = s.db.AutoMigrate(&model.Problem{}) + _ = s.db.AutoMigrate(&model.ProblemVersion{}) + _ = s.db.AutoMigrate(&model.Submission{}) + _ = s.db.AutoMigrate(&model.Status{}) + + s.err = s.db.Exec("SELECT pg_advisory_unlock(?)", lockID).Error + if s.err != nil { + s.log.Error("Failed to release lock", zap.Error(s.err)) + } +} + +func (s *service) HealthCheck() error { + return s.err +} + +func (s *service) Shutdown() error { var db *sql.DB db, s.err = s.db.DB() if s.err != nil { @@ -57,14 +94,6 @@ func (s *service) Close() error { return s.err } -func (s *service) HealthCheck() error { - return s.err -} - -func (s *service) Shutdown() error { - return s.Close() -} - func (s *service) setup(conf *model.Config) { s.log.Info("Connecting to database...") @@ -109,41 +138,6 @@ func (s *service) setup(conf *model.Config) { db.SetMaxOpenConns(conf.Database.MaxOpenConns) db.SetMaxIdleConns(conf.Database.MaxIdleConns) db.SetConnMaxLifetime(time.Duration(conf.Database.ConnMaxLifetime) * time.Minute) - - s.migrateDatabase() -} - -func (s *service) migrateDatabase() { - s.log.Info("Auto Migrating database...") - - // Running AutoMigrate concurrently on the same model fails with various race conditions - // https://github.com/go-gorm/gorm/pull/6680 - // https://github.com/go-gorm/postgres/pull/224 - - // Obtain a lock to prevent concurrent AutoMigrate - - lockID := func(s string) int64 { - h := fnv.New64a() - _, err := h.Write([]byte(s)) - return utils.If(err != nil, int64(0x4242AA55), int64(h.Sum64())) - }("gorm:migrator") - - s.err = s.db.Exec("SELECT pg_advisory_lock(?)", lockID).Error - if s.err != nil { - s.log.Error("Failed to obtain lock", zap.Error(s.err)) - return - } - - _ = s.db.AutoMigrate(&model.User{}) - _ = s.db.AutoMigrate(&model.Problem{}) - _ = s.db.AutoMigrate(&model.ProblemVersion{}) - _ = s.db.AutoMigrate(&model.Submission{}) - _ = s.db.AutoMigrate(&model.Status{}) - - s.err = s.db.Exec("SELECT pg_advisory_unlock(?)", lockID).Error - if s.err != nil { - s.log.Error("Failed to release lock", zap.Error(s.err)) - } } func (s *service) checkAlive(retry int) (*sql.DB, error) {