feat(ops): add usage_logs partitioning check at deployment startup
Some checks failed
CI / test (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled

Add CheckUsageLogsPartitioning function that:
- Checks if usage_logs table is partitioned
- Warns with prominent banner if not partitioned and rows > 100K
- Provides actionable guidance for manual partition migration

This helps operators identify performance risks early and take
appropriate action before data volume causes issues.
This commit is contained in:
User
2026-04-16 22:11:15 +08:00
parent 64b971a3dc
commit eb5adbbae5
2 changed files with 56 additions and 1 deletions

View File

@@ -8,6 +8,7 @@ import (
"errors"
"fmt"
"io/fs"
"log"
"sort"
"strings"
"time"
@@ -432,3 +433,51 @@ func pgAdvisoryUnlock(ctx context.Context, db *sql.DB) error {
}
return nil
}
// CheckUsageLogsPartitioning 检查 usage_logs 表是否已分区。
// 如未分区且数据量较大,会输出醒目的警告提示运维人员考虑分区。
func CheckUsageLogsPartitioning(ctx context.Context, db *sql.DB) {
var isPartitioned bool
err := db.QueryRowContext(ctx, `
SELECT EXISTS(
SELECT 1
FROM pg_partitioned_table pt
JOIN pg_class c ON c.oid = pt.partrelid
WHERE c.relname = 'usage_logs'
)
`).Scan(&isPartitioned)
if err != nil {
// 查询失败时静默忽略,不影响启动
return
}
if isPartitioned {
return
}
// 检查数据量
var rowCount int64
err = db.QueryRowContext(ctx, `SELECT COUNT(*) FROM usage_logs`).Scan(&rowCount)
if err != nil {
return
}
// 数据量小于 10 万行时,分区不那么紧急
if rowCount < 100000 {
return
}
// 数据量较大且未分区,输出醒目警告
log.Printf("================================================================================")
log.Printf("⚠️ PERFORMANCE WARNING: usage_logs table is NOT partitioned")
log.Printf(" Current rows: %d (threshold: 100,000)", rowCount)
log.Printf(" Large unpartitioned tables can cause:")
log.Printf(" - Slow queries and dashboard latency")
log.Printf(" - Index bloat and maintenance overhead")
log.Printf(" - Longer backup/restore times")
log.Printf(" Recommended actions:")
log.Printf(" 1. Review migrations/035_usage_logs_partitioning.sql for manual migration")
log.Printf(" 2. Plan partition conversion during low-traffic window")
log.Printf(" 3. Ensure UsageCleanupConfig is enabled for automatic cleanup")
log.Printf("================================================================================")
}

View File

@@ -362,7 +362,13 @@ func initializeDatabase(cfg *SetupConfig) error {
migrationCtx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
return repository.ApplyMigrations(migrationCtx, db)
if err := repository.ApplyMigrations(migrationCtx, db); err != nil {
return err
}
// 检查 usage_logs 分区状态(仅在首次部署时提示)
repository.CheckUsageLogsPartitioning(migrationCtx, db)
return nil
}
func createAdminUser(cfg *SetupConfig) (bool, string, error) {