From bef55bd11fb1352c74f6f10cb397cf343fdf44d2 Mon Sep 17 00:00:00 2001 From: liangxu Date: Wed, 29 Apr 2026 17:10:48 +0800 Subject: [PATCH] feat(ops-api/site-mappings): provision monitoring DB pool and readiness check Open a separate pgx pool for the monitoring database, wire it into the SiteDomainMappingService, and surface its health in /readyz. Point compose at the dedicated monitoring-postgres service and align local/dev configs with the per-instance ports. Also reformat the site_domain_mapping types with gofmt while the files are touched. Co-Authored-By: Claude Opus 4.7 (1M context) --- deploy/docker-compose.yaml | 2 + deploy/ops-config.yaml | 2 +- server/cmd/ops-api/main.go | 26 ++++++--- server/configs/ops-config.yaml | 2 +- .../internal/ops/app/site_domain_mapping.go | 56 +++++++++---------- server/internal/ops/domain/types.go | 12 ++-- .../ops/repository/site_domain_mapping.go | 12 ++-- server/internal/ops/transport/router.go | 25 ++++++--- .../transport/site_domain_mapping_handler.go | 12 ++-- 9 files changed, 84 insertions(+), 65 deletions(-) diff --git a/deploy/docker-compose.yaml b/deploy/docker-compose.yaml index 195690c..2e84243 100644 --- a/deploy/docker-compose.yaml +++ b/deploy/docker-compose.yaml @@ -240,6 +240,8 @@ services: depends_on: postgres: condition: service_healthy + monitoring-postgres: + condition: service_healthy migrate: condition: service_completed_successfully ports: diff --git a/deploy/ops-config.yaml b/deploy/ops-config.yaml index 4825ef0..128f154 100644 --- a/deploy/ops-config.yaml +++ b/deploy/ops-config.yaml @@ -13,7 +13,7 @@ database: max_idle_conns: 2 monitoring_database: - host: postgres + host: monitoring-postgres port: 5432 user: geo password: geo_dev diff --git a/server/cmd/ops-api/main.go b/server/cmd/ops-api/main.go index a6d52c4..366690f 100644 --- a/server/cmd/ops-api/main.go +++ b/server/cmd/ops-api/main.go @@ -44,9 +44,16 @@ func main() { } defer pool.Close() + monitoringPool, err := postgres.NewPool(ctx, cfg.MonitoringDatabase) + if err != nil { + logger.Sugar().Fatalf("ops-api init monitoring postgres: %v", err) + } + defer monitoringPool.Close() + accountsRepo := repository.NewAccountRepository(pool) adminUsersRepo := repository.NewAdminUserRepository(pool) auditsRepo := repository.NewAuditRepository(pool) + siteDomainMappingsRepo := repository.NewSiteDomainMappingRepository(monitoringPool) ipRegionResolver, err := app.NewIPRegionResolver(cfg.IPRegion.V4XDBPath, cfg.IPRegion.V6XDBPath, logger) if err != nil { @@ -59,6 +66,7 @@ func main() { authSvc := app.NewAuthService(accountsRepo, auditSvc, issuer) accountSvc := app.NewAccountService(accountsRepo, auditSvc) adminUserSvc := app.NewAdminUserService(adminUsersRepo, auditSvc, cfg.AdminUsers.DefaultPlanCode) + siteDomainMappingSvc := app.NewSiteDomainMappingService(siteDomainMappingsRepo, auditSvc) if err := app.SeedDefaultAdmin(ctx, accountsRepo, app.DefaultAdminSeed{ Username: cfg.DefaultAdmin.Username, @@ -75,14 +83,16 @@ func main() { engine := gin.New() transport.RegisterRoutes(transport.Deps{ - Engine: engine, - Logger: logger, - DB: pool, - Issuer: issuer, - Auth: authSvc, - Accounts: accountSvc, - AdminUsers: adminUserSvc, - Audits: auditSvc, + Engine: engine, + Logger: logger, + DB: pool, + MonitoringDB: monitoringPool, + Issuer: issuer, + Auth: authSvc, + Accounts: accountSvc, + AdminUsers: adminUserSvc, + Audits: auditSvc, + SiteDomains: siteDomainMappingSvc, }) addr := fmt.Sprintf(":%d", cfg.Server.Port) diff --git a/server/configs/ops-config.yaml b/server/configs/ops-config.yaml index 23bff01..0cdc960 100644 --- a/server/configs/ops-config.yaml +++ b/server/configs/ops-config.yaml @@ -14,7 +14,7 @@ database: monitoring_database: host: localhost - port: 5432 + port: 5433 user: geo password: geo_dev dbname: geo_monitoring diff --git a/server/internal/ops/app/site_domain_mapping.go b/server/internal/ops/app/site_domain_mapping.go index ae5c90c..4886085 100644 --- a/server/internal/ops/app/site_domain_mapping.go +++ b/server/internal/ops/app/site_domain_mapping.go @@ -16,11 +16,11 @@ import ( ) const ( - ActionSiteDomainMappingCreate = "site_domain_mapping.create" - ActionSiteDomainMappingUpdate = "site_domain_mapping.update" - ActionSiteDomainMappingEnable = "site_domain_mapping.enable" + ActionSiteDomainMappingCreate = "site_domain_mapping.create" + ActionSiteDomainMappingUpdate = "site_domain_mapping.update" + ActionSiteDomainMappingEnable = "site_domain_mapping.enable" ActionSiteDomainMappingDisable = "site_domain_mapping.disable" - ActionSiteDomainMappingDelete = "site_domain_mapping.delete" + ActionSiteDomainMappingDelete = "site_domain_mapping.delete" ) type SiteDomainMappingService struct { @@ -33,13 +33,13 @@ func NewSiteDomainMappingService(mappings *repository.SiteDomainMappingRepositor } type SiteDomainMappingView struct { - ID int64 `json:"id"` + ID int64 `json:"id"` RegistrableDomain string `json:"registrable_domain"` - SiteKey string `json:"site_key"` - SiteName string `json:"site_name"` - IsActive bool `json:"is_active"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + SiteKey string `json:"site_key"` + SiteName string `json:"site_name"` + IsActive bool `json:"is_active"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } type SiteDomainMappingListInput struct { @@ -58,20 +58,20 @@ type SiteDomainMappingListResult struct { type SiteDomainMappingInput struct { RegistrableDomain string - SiteKey string - SiteName string - IsActive bool + SiteKey string + SiteName string + IsActive bool } func toSiteDomainMappingView(item *domain.SiteDomainMapping) SiteDomainMappingView { return SiteDomainMappingView{ - ID: item.ID, + ID: item.ID, RegistrableDomain: item.RegistrableDomain, - SiteKey: item.SiteKey, - SiteName: item.SiteName, - IsActive: item.IsActive, - CreatedAt: item.CreatedAt, - UpdatedAt: item.UpdatedAt, + SiteKey: item.SiteKey, + SiteName: item.SiteName, + IsActive: item.IsActive, + CreatedAt: item.CreatedAt, + UpdatedAt: item.UpdatedAt, } } @@ -109,9 +109,9 @@ func (s *SiteDomainMappingService) Create(ctx context.Context, actor *Actor, in } item, err := s.mappings.Create(ctx, repository.CreateSiteDomainMappingInput{ RegistrableDomain: normalized.RegistrableDomain, - SiteKey: normalized.SiteKey, - SiteName: normalized.SiteName, - IsActive: normalized.IsActive, + SiteKey: normalized.SiteKey, + SiteName: normalized.SiteName, + IsActive: normalized.IsActive, }) if err != nil { if isDuplicateSiteDomainMapping(err) { @@ -133,9 +133,9 @@ func (s *SiteDomainMappingService) Update(ctx context.Context, actor *Actor, id } item, err := s.mappings.Update(ctx, id, repository.UpdateSiteDomainMappingInput{ RegistrableDomain: normalized.RegistrableDomain, - SiteKey: normalized.SiteKey, - SiteName: normalized.SiteName, - IsActive: normalized.IsActive, + SiteKey: normalized.SiteKey, + SiteName: normalized.SiteName, + IsActive: normalized.IsActive, }) if err != nil { if errors.Is(err, repository.ErrSiteDomainMappingNotFound) { @@ -213,9 +213,9 @@ func normalizeSiteDomainMappingInput(in SiteDomainMappingInput) (SiteDomainMappi return SiteDomainMappingInput{ RegistrableDomain: domainName, - SiteKey: siteKey, - SiteName: siteName, - IsActive: in.IsActive, + SiteKey: siteKey, + SiteName: siteName, + IsActive: in.IsActive, }, nil } diff --git a/server/internal/ops/domain/types.go b/server/internal/ops/domain/types.go index 7af5bc3..c821819 100644 --- a/server/internal/ops/domain/types.go +++ b/server/internal/ops/domain/types.go @@ -65,11 +65,11 @@ type AuditLogFilter struct { } type SiteDomainMapping struct { - ID int64 + ID int64 RegistrableDomain string - SiteKey string - SiteName string - IsActive bool - CreatedAt time.Time - UpdatedAt time.Time + SiteKey string + SiteName string + IsActive bool + CreatedAt time.Time + UpdatedAt time.Time } diff --git a/server/internal/ops/repository/site_domain_mapping.go b/server/internal/ops/repository/site_domain_mapping.go index c9e76a1..5dfe285 100644 --- a/server/internal/ops/repository/site_domain_mapping.go +++ b/server/internal/ops/repository/site_domain_mapping.go @@ -32,16 +32,16 @@ type SiteDomainMappingFilter struct { type CreateSiteDomainMappingInput struct { RegistrableDomain string - SiteKey string - SiteName string - IsActive bool + SiteKey string + SiteName string + IsActive bool } type UpdateSiteDomainMappingInput struct { RegistrableDomain string - SiteKey string - SiteName string - IsActive bool + SiteKey string + SiteName string + IsActive bool } func scanSiteDomainMapping(row pgx.Row) (*domain.SiteDomainMapping, error) { diff --git a/server/internal/ops/transport/router.go b/server/internal/ops/transport/router.go index 444d52c..ac0e9e4 100644 --- a/server/internal/ops/transport/router.go +++ b/server/internal/ops/transport/router.go @@ -11,15 +11,16 @@ import ( ) type Deps struct { - Engine *gin.Engine - Logger *zap.Logger - DB *pgxpool.Pool - Issuer *app.TokenIssuer - Auth *app.AuthService - Accounts *app.AccountService - AdminUsers *app.AdminUserService - Audits *app.AuditService - SiteDomains *app.SiteDomainMappingService + Engine *gin.Engine + Logger *zap.Logger + DB *pgxpool.Pool + MonitoringDB *pgxpool.Pool + Issuer *app.TokenIssuer + Auth *app.AuthService + Accounts *app.AccountService + AdminUsers *app.AdminUserService + Audits *app.AuditService + SiteDomains *app.SiteDomainMappingService } func RegisterRoutes(d Deps) { @@ -38,6 +39,12 @@ func RegisterRoutes(d Deps) { response.Error(c, response.ErrServiceUnavailable(50301, "postgres_unavailable", "数据库不可达")) return } + if d.MonitoringDB != nil { + if err := d.MonitoringDB.Ping(c.Request.Context()); err != nil { + response.Error(c, response.ErrServiceUnavailable(50303, "monitoring_postgres_unavailable", "监控数据库不可达")) + return + } + } response.Success(c, gin.H{"status": "ready"}) }) diff --git a/server/internal/ops/transport/site_domain_mapping_handler.go b/server/internal/ops/transport/site_domain_mapping_handler.go index e14a8ff..ceb3b83 100644 --- a/server/internal/ops/transport/site_domain_mapping_handler.go +++ b/server/internal/ops/transport/site_domain_mapping_handler.go @@ -11,9 +11,9 @@ import ( type siteDomainMappingRequest struct { RegistrableDomain string `json:"registrable_domain" binding:"required"` - SiteKey string `json:"site_key"` - SiteName string `json:"site_name" binding:"required"` - IsActive *bool `json:"is_active"` + SiteKey string `json:"site_key"` + SiteName string `json:"site_name" binding:"required"` + IsActive *bool `json:"is_active"` } type setSiteDomainMappingActiveRequest struct { @@ -118,9 +118,9 @@ func (r siteDomainMappingRequest) toInput() app.SiteDomainMappingInput { } return app.SiteDomainMappingInput{ RegistrableDomain: r.RegistrableDomain, - SiteKey: r.SiteKey, - SiteName: r.SiteName, - IsActive: active, + SiteKey: r.SiteKey, + SiteName: r.SiteName, + IsActive: active, } }