topfans/backend/services/statisticService/config/statistic_config.go
zerosaturation f5ece5e1d2 feat(statistic): T3 service skeleton (config + main + healthz + metrics + 10 SQL)
- 6 config blocks (DB/Redis/Channel/Refresh/Partition/Extension with 4 EnableXxx=false)
- 14 Prometheus metric declarations
- self-impl healthz (/healthz + /metrics) — bypasses pkg/health to keep /metrics
- main.go startup: logger → config → DB → Redis → healthz HTTP :21009
- 10 SQL migrations: events partitioned + 4 MV + 3 pre-agg + refresh_log + 7-day initial

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 17:20:53 +08:00

156 lines
5.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package config
import (
"flag"
"log"
"os"
"strconv"
"time"
)
// DatabaseConfig 数据库配置
type DatabaseConfig struct {
Host, Password, DBName, SSLMode, TimeZone string
Port int
User string
Schema string
}
// RedisConfig Redis 配置
type RedisConfig struct {
URL string
}
// RefreshIntervals 物化视图/预聚表刷新间隔
type RefreshIntervals struct {
DailyUserIncome time.Duration
DailyExhibitionRevenue time.Duration
DailyLikeIncome time.Duration
AssetLevelDistribution time.Duration
WeeklyUserIncome time.Duration
UpcomingLevelUps time.Duration
}
// ChannelConfig 事件 channel 配置
type ChannelConfig struct {
EventChannelCapacity int
EventWorkerCount int
EventBatchSize int
EventBatchInterval time.Duration
}
// PartitionConfig 分区管理配置
type PartitionConfig struct {
RetentionDays int
PreCreateDays int
}
// ExtensionConfig 预留扩展开关
type ExtensionConfig struct {
EnableOLAPDualWrite bool
EnableRealtimeChannel bool
EnableSDKEndpoint bool
EnableSampling bool
}
var (
DBConfig = &DatabaseConfig{
Schema: "statistic",
}
RedisCfg = &RedisConfig{
URL: "redis://localhost:6379/0",
}
RefreshCfg = &RefreshIntervals{
DailyUserIncome: 5 * time.Minute,
DailyExhibitionRevenue: 5 * time.Minute,
DailyLikeIncome: 5 * time.Minute,
AssetLevelDistribution: 15 * time.Minute,
WeeklyUserIncome: 5 * time.Minute,
UpcomingLevelUps: 15 * time.Minute,
}
ChannelCfg = &ChannelConfig{
EventChannelCapacity: 1000,
EventWorkerCount: 1,
EventBatchSize: 100,
EventBatchInterval: 1 * time.Second,
}
PartitionCfg = &PartitionConfig{
RetentionDays: 30,
PreCreateDays: 7,
}
ExtCfg = &ExtensionConfig{ // 全部默认 false本期不启用
EnableOLAPDualWrite: false,
EnableRealtimeChannel: false,
EnableSDKEndpoint: false,
EnableSampling: false,
}
)
func getEnv(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}
func getEnvInt(key string, fallback int) int {
if v := os.Getenv(key); v != "" {
if n, err := strconv.Atoi(v); err == nil {
return n
}
}
return fallback
}
func getEnvDuration(key string, fallback time.Duration) time.Duration {
if v := os.Getenv(key); v != "" {
if d, err := time.ParseDuration(v); err == nil {
return d
}
}
return fallback
}
func getEnvBool(key string, fallback bool) bool {
if v := os.Getenv(key); v != "" {
if b, err := strconv.ParseBool(v); err == nil {
return b
}
}
return fallback
}
// InitConfig 初始化所有配置flag + 环境变量)
func InitConfig() {
flag.StringVar(&DBConfig.Host, "db-host", getEnv("STATISTIC_DB_HOST", "localhost"), "数据库主机")
flag.IntVar(&DBConfig.Port, "db-port", getEnvInt("STATISTIC_DB_PORT", 5432), "数据库端口")
flag.StringVar(&DBConfig.User, "db-user", getEnv("STATISTIC_DB_USER", "postgres"), "数据库用户")
flag.StringVar(&DBConfig.Password, "db-password", getEnv("STATISTIC_DB_PASSWORD", ""), "数据库密码")
flag.StringVar(&DBConfig.DBName, "db-name", getEnv("STATISTIC_DB_NAME", "topfans"), "数据库名")
flag.StringVar(&DBConfig.SSLMode, "db-sslmode", "disable", "数据库 SSL 模式")
flag.StringVar(&DBConfig.Schema, "db-schema", getEnv("STATISTIC_DB_SCHEMA", "statistic"), "数据库 schema")
flag.StringVar(&RedisCfg.URL, "redis-url", getEnv("STATISTIC_REDIS_URL", "redis://localhost:6379/0"), "Redis URL")
flag.IntVar(&ChannelCfg.EventChannelCapacity, "event-channel-capacity", getEnvInt("STATISTIC_EVENT_CHANNEL_CAPACITY", 1000), "事件 channel 容量")
flag.IntVar(&ChannelCfg.EventBatchSize, "event-batch-size", getEnvInt("STATISTIC_EVENT_BATCH_SIZE", 100), "事件批量大小")
flag.DurationVar(&ChannelCfg.EventBatchInterval, "event-batch-interval", getEnvDuration("STATISTIC_EVENT_BATCH_INTERVAL", time.Second), "事件批量间隔")
flag.IntVar(&PartitionCfg.RetentionDays, "partition-retention-days", getEnvInt("STATISTIC_PARTITION_RETENTION_DAYS", 30), "分区保留天数")
flag.IntVar(&PartitionCfg.PreCreateDays, "partition-precreate-days", getEnvInt("STATISTIC_PARTITION_PRECREATE_DAYS", 7), "分区预创建天数")
flag.BoolVar(&ExtCfg.EnableOLAPDualWrite, "enable-olap", getEnvBool("STATISTIC_ENABLE_OLAP_DUAL_WRITE", false), "启用 OLAP 双写")
flag.BoolVar(&ExtCfg.EnableRealtimeChannel, "enable-realtime", getEnvBool("STATISTIC_ENABLE_REALTIME_CHANNEL", false), "启用实时通道")
flag.BoolVar(&ExtCfg.EnableSDKEndpoint, "enable-sdk", getEnvBool("STATISTIC_ENABLE_SDK_ENDPOINT", false), "启用 SDK 端点")
flag.BoolVar(&ExtCfg.EnableSampling, "enable-sampling", getEnvBool("STATISTIC_ENABLE_SAMPLING", false), "启用采样")
flag.Parse()
log.Println("statisticService 配置初始化完成")
log.Printf(" 数据库: %s:%d/%s (schema=%s)", DBConfig.Host, DBConfig.Port, DBConfig.DBName, DBConfig.Schema)
log.Printf(" Redis: %s", RedisCfg.URL)
log.Printf(" 事件 channel 容量: %d, 批量: %d/%v", ChannelCfg.EventChannelCapacity, ChannelCfg.EventBatchSize, ChannelCfg.EventBatchInterval)
log.Printf(" 分区保留: %d 天, 预创建: %d 天", PartitionCfg.RetentionDays, PartitionCfg.PreCreateDays)
log.Printf(" 扩展开关: OLAP=%v Realtime=%v SDK=%v Sampling=%v",
ExtCfg.EnableOLAPDualWrite, ExtCfg.EnableRealtimeChannel, ExtCfg.EnableSDKEndpoint, ExtCfg.EnableSampling)
}