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) <noreply@anthropic.com>
This commit is contained in:
@@ -240,6 +240,8 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
monitoring-postgres:
|
||||||
|
condition: service_healthy
|
||||||
migrate:
|
migrate:
|
||||||
condition: service_completed_successfully
|
condition: service_completed_successfully
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ database:
|
|||||||
max_idle_conns: 2
|
max_idle_conns: 2
|
||||||
|
|
||||||
monitoring_database:
|
monitoring_database:
|
||||||
host: postgres
|
host: monitoring-postgres
|
||||||
port: 5432
|
port: 5432
|
||||||
user: geo
|
user: geo
|
||||||
password: geo_dev
|
password: geo_dev
|
||||||
|
|||||||
@@ -44,9 +44,16 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer pool.Close()
|
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)
|
accountsRepo := repository.NewAccountRepository(pool)
|
||||||
adminUsersRepo := repository.NewAdminUserRepository(pool)
|
adminUsersRepo := repository.NewAdminUserRepository(pool)
|
||||||
auditsRepo := repository.NewAuditRepository(pool)
|
auditsRepo := repository.NewAuditRepository(pool)
|
||||||
|
siteDomainMappingsRepo := repository.NewSiteDomainMappingRepository(monitoringPool)
|
||||||
|
|
||||||
ipRegionResolver, err := app.NewIPRegionResolver(cfg.IPRegion.V4XDBPath, cfg.IPRegion.V6XDBPath, logger)
|
ipRegionResolver, err := app.NewIPRegionResolver(cfg.IPRegion.V4XDBPath, cfg.IPRegion.V6XDBPath, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -59,6 +66,7 @@ func main() {
|
|||||||
authSvc := app.NewAuthService(accountsRepo, auditSvc, issuer)
|
authSvc := app.NewAuthService(accountsRepo, auditSvc, issuer)
|
||||||
accountSvc := app.NewAccountService(accountsRepo, auditSvc)
|
accountSvc := app.NewAccountService(accountsRepo, auditSvc)
|
||||||
adminUserSvc := app.NewAdminUserService(adminUsersRepo, auditSvc, cfg.AdminUsers.DefaultPlanCode)
|
adminUserSvc := app.NewAdminUserService(adminUsersRepo, auditSvc, cfg.AdminUsers.DefaultPlanCode)
|
||||||
|
siteDomainMappingSvc := app.NewSiteDomainMappingService(siteDomainMappingsRepo, auditSvc)
|
||||||
|
|
||||||
if err := app.SeedDefaultAdmin(ctx, accountsRepo, app.DefaultAdminSeed{
|
if err := app.SeedDefaultAdmin(ctx, accountsRepo, app.DefaultAdminSeed{
|
||||||
Username: cfg.DefaultAdmin.Username,
|
Username: cfg.DefaultAdmin.Username,
|
||||||
@@ -75,14 +83,16 @@ func main() {
|
|||||||
engine := gin.New()
|
engine := gin.New()
|
||||||
|
|
||||||
transport.RegisterRoutes(transport.Deps{
|
transport.RegisterRoutes(transport.Deps{
|
||||||
Engine: engine,
|
Engine: engine,
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
DB: pool,
|
DB: pool,
|
||||||
Issuer: issuer,
|
MonitoringDB: monitoringPool,
|
||||||
Auth: authSvc,
|
Issuer: issuer,
|
||||||
Accounts: accountSvc,
|
Auth: authSvc,
|
||||||
AdminUsers: adminUserSvc,
|
Accounts: accountSvc,
|
||||||
Audits: auditSvc,
|
AdminUsers: adminUserSvc,
|
||||||
|
Audits: auditSvc,
|
||||||
|
SiteDomains: siteDomainMappingSvc,
|
||||||
})
|
})
|
||||||
|
|
||||||
addr := fmt.Sprintf(":%d", cfg.Server.Port)
|
addr := fmt.Sprintf(":%d", cfg.Server.Port)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ database:
|
|||||||
|
|
||||||
monitoring_database:
|
monitoring_database:
|
||||||
host: localhost
|
host: localhost
|
||||||
port: 5432
|
port: 5433
|
||||||
user: geo
|
user: geo
|
||||||
password: geo_dev
|
password: geo_dev
|
||||||
dbname: geo_monitoring
|
dbname: geo_monitoring
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ActionSiteDomainMappingCreate = "site_domain_mapping.create"
|
ActionSiteDomainMappingCreate = "site_domain_mapping.create"
|
||||||
ActionSiteDomainMappingUpdate = "site_domain_mapping.update"
|
ActionSiteDomainMappingUpdate = "site_domain_mapping.update"
|
||||||
ActionSiteDomainMappingEnable = "site_domain_mapping.enable"
|
ActionSiteDomainMappingEnable = "site_domain_mapping.enable"
|
||||||
ActionSiteDomainMappingDisable = "site_domain_mapping.disable"
|
ActionSiteDomainMappingDisable = "site_domain_mapping.disable"
|
||||||
ActionSiteDomainMappingDelete = "site_domain_mapping.delete"
|
ActionSiteDomainMappingDelete = "site_domain_mapping.delete"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SiteDomainMappingService struct {
|
type SiteDomainMappingService struct {
|
||||||
@@ -33,13 +33,13 @@ func NewSiteDomainMappingService(mappings *repository.SiteDomainMappingRepositor
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SiteDomainMappingView struct {
|
type SiteDomainMappingView struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
RegistrableDomain string `json:"registrable_domain"`
|
RegistrableDomain string `json:"registrable_domain"`
|
||||||
SiteKey string `json:"site_key"`
|
SiteKey string `json:"site_key"`
|
||||||
SiteName string `json:"site_name"`
|
SiteName string `json:"site_name"`
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SiteDomainMappingListInput struct {
|
type SiteDomainMappingListInput struct {
|
||||||
@@ -58,20 +58,20 @@ type SiteDomainMappingListResult struct {
|
|||||||
|
|
||||||
type SiteDomainMappingInput struct {
|
type SiteDomainMappingInput struct {
|
||||||
RegistrableDomain string
|
RegistrableDomain string
|
||||||
SiteKey string
|
SiteKey string
|
||||||
SiteName string
|
SiteName string
|
||||||
IsActive bool
|
IsActive bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func toSiteDomainMappingView(item *domain.SiteDomainMapping) SiteDomainMappingView {
|
func toSiteDomainMappingView(item *domain.SiteDomainMapping) SiteDomainMappingView {
|
||||||
return SiteDomainMappingView{
|
return SiteDomainMappingView{
|
||||||
ID: item.ID,
|
ID: item.ID,
|
||||||
RegistrableDomain: item.RegistrableDomain,
|
RegistrableDomain: item.RegistrableDomain,
|
||||||
SiteKey: item.SiteKey,
|
SiteKey: item.SiteKey,
|
||||||
SiteName: item.SiteName,
|
SiteName: item.SiteName,
|
||||||
IsActive: item.IsActive,
|
IsActive: item.IsActive,
|
||||||
CreatedAt: item.CreatedAt,
|
CreatedAt: item.CreatedAt,
|
||||||
UpdatedAt: item.UpdatedAt,
|
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{
|
item, err := s.mappings.Create(ctx, repository.CreateSiteDomainMappingInput{
|
||||||
RegistrableDomain: normalized.RegistrableDomain,
|
RegistrableDomain: normalized.RegistrableDomain,
|
||||||
SiteKey: normalized.SiteKey,
|
SiteKey: normalized.SiteKey,
|
||||||
SiteName: normalized.SiteName,
|
SiteName: normalized.SiteName,
|
||||||
IsActive: normalized.IsActive,
|
IsActive: normalized.IsActive,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isDuplicateSiteDomainMapping(err) {
|
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{
|
item, err := s.mappings.Update(ctx, id, repository.UpdateSiteDomainMappingInput{
|
||||||
RegistrableDomain: normalized.RegistrableDomain,
|
RegistrableDomain: normalized.RegistrableDomain,
|
||||||
SiteKey: normalized.SiteKey,
|
SiteKey: normalized.SiteKey,
|
||||||
SiteName: normalized.SiteName,
|
SiteName: normalized.SiteName,
|
||||||
IsActive: normalized.IsActive,
|
IsActive: normalized.IsActive,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, repository.ErrSiteDomainMappingNotFound) {
|
if errors.Is(err, repository.ErrSiteDomainMappingNotFound) {
|
||||||
@@ -213,9 +213,9 @@ func normalizeSiteDomainMappingInput(in SiteDomainMappingInput) (SiteDomainMappi
|
|||||||
|
|
||||||
return SiteDomainMappingInput{
|
return SiteDomainMappingInput{
|
||||||
RegistrableDomain: domainName,
|
RegistrableDomain: domainName,
|
||||||
SiteKey: siteKey,
|
SiteKey: siteKey,
|
||||||
SiteName: siteName,
|
SiteName: siteName,
|
||||||
IsActive: in.IsActive,
|
IsActive: in.IsActive,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,11 +65,11 @@ type AuditLogFilter struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SiteDomainMapping struct {
|
type SiteDomainMapping struct {
|
||||||
ID int64
|
ID int64
|
||||||
RegistrableDomain string
|
RegistrableDomain string
|
||||||
SiteKey string
|
SiteKey string
|
||||||
SiteName string
|
SiteName string
|
||||||
IsActive bool
|
IsActive bool
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,16 +32,16 @@ type SiteDomainMappingFilter struct {
|
|||||||
|
|
||||||
type CreateSiteDomainMappingInput struct {
|
type CreateSiteDomainMappingInput struct {
|
||||||
RegistrableDomain string
|
RegistrableDomain string
|
||||||
SiteKey string
|
SiteKey string
|
||||||
SiteName string
|
SiteName string
|
||||||
IsActive bool
|
IsActive bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateSiteDomainMappingInput struct {
|
type UpdateSiteDomainMappingInput struct {
|
||||||
RegistrableDomain string
|
RegistrableDomain string
|
||||||
SiteKey string
|
SiteKey string
|
||||||
SiteName string
|
SiteName string
|
||||||
IsActive bool
|
IsActive bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func scanSiteDomainMapping(row pgx.Row) (*domain.SiteDomainMapping, error) {
|
func scanSiteDomainMapping(row pgx.Row) (*domain.SiteDomainMapping, error) {
|
||||||
|
|||||||
@@ -11,15 +11,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Deps struct {
|
type Deps struct {
|
||||||
Engine *gin.Engine
|
Engine *gin.Engine
|
||||||
Logger *zap.Logger
|
Logger *zap.Logger
|
||||||
DB *pgxpool.Pool
|
DB *pgxpool.Pool
|
||||||
Issuer *app.TokenIssuer
|
MonitoringDB *pgxpool.Pool
|
||||||
Auth *app.AuthService
|
Issuer *app.TokenIssuer
|
||||||
Accounts *app.AccountService
|
Auth *app.AuthService
|
||||||
AdminUsers *app.AdminUserService
|
Accounts *app.AccountService
|
||||||
Audits *app.AuditService
|
AdminUsers *app.AdminUserService
|
||||||
SiteDomains *app.SiteDomainMappingService
|
Audits *app.AuditService
|
||||||
|
SiteDomains *app.SiteDomainMappingService
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisterRoutes(d Deps) {
|
func RegisterRoutes(d Deps) {
|
||||||
@@ -38,6 +39,12 @@ func RegisterRoutes(d Deps) {
|
|||||||
response.Error(c, response.ErrServiceUnavailable(50301, "postgres_unavailable", "数据库不可达"))
|
response.Error(c, response.ErrServiceUnavailable(50301, "postgres_unavailable", "数据库不可达"))
|
||||||
return
|
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"})
|
response.Success(c, gin.H{"status": "ready"})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import (
|
|||||||
|
|
||||||
type siteDomainMappingRequest struct {
|
type siteDomainMappingRequest struct {
|
||||||
RegistrableDomain string `json:"registrable_domain" binding:"required"`
|
RegistrableDomain string `json:"registrable_domain" binding:"required"`
|
||||||
SiteKey string `json:"site_key"`
|
SiteKey string `json:"site_key"`
|
||||||
SiteName string `json:"site_name" binding:"required"`
|
SiteName string `json:"site_name" binding:"required"`
|
||||||
IsActive *bool `json:"is_active"`
|
IsActive *bool `json:"is_active"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type setSiteDomainMappingActiveRequest struct {
|
type setSiteDomainMappingActiveRequest struct {
|
||||||
@@ -118,9 +118,9 @@ func (r siteDomainMappingRequest) toInput() app.SiteDomainMappingInput {
|
|||||||
}
|
}
|
||||||
return app.SiteDomainMappingInput{
|
return app.SiteDomainMappingInput{
|
||||||
RegistrableDomain: r.RegistrableDomain,
|
RegistrableDomain: r.RegistrableDomain,
|
||||||
SiteKey: r.SiteKey,
|
SiteKey: r.SiteKey,
|
||||||
SiteName: r.SiteName,
|
SiteName: r.SiteName,
|
||||||
IsActive: active,
|
IsActive: active,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user