feat: use postgres
This commit is contained in:
@@ -3,15 +3,18 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"galaxy/lobby/internal/telemetry"
|
||||
"galaxy/postgres"
|
||||
"galaxy/redisconn"
|
||||
)
|
||||
|
||||
const (
|
||||
envPrefix = "LOBBY"
|
||||
|
||||
shutdownTimeoutEnvVar = "LOBBY_SHUTDOWN_TIMEOUT"
|
||||
logLevelEnvVar = "LOBBY_LOG_LEVEL"
|
||||
|
||||
@@ -25,13 +28,6 @@ const (
|
||||
internalHTTPReadTimeoutEnvVar = "LOBBY_INTERNAL_HTTP_READ_TIMEOUT"
|
||||
internalHTTPIdleTimeoutEnvVar = "LOBBY_INTERNAL_HTTP_IDLE_TIMEOUT"
|
||||
|
||||
redisAddrEnvVar = "LOBBY_REDIS_ADDR"
|
||||
redisUsernameEnvVar = "LOBBY_REDIS_USERNAME"
|
||||
redisPasswordEnvVar = "LOBBY_REDIS_PASSWORD"
|
||||
redisDBEnvVar = "LOBBY_REDIS_DB"
|
||||
redisTLSEnabledEnvVar = "LOBBY_REDIS_TLS_ENABLED"
|
||||
redisOperationTimeoutEnvVar = "LOBBY_REDIS_OPERATION_TIMEOUT"
|
||||
|
||||
gmEventsStreamEnvVar = "LOBBY_GM_EVENTS_STREAM"
|
||||
gmEventsReadBlockTimeoutEnvVar = "LOBBY_GM_EVENTS_READ_BLOCK_TIMEOUT"
|
||||
userLifecycleStreamEnvVar = "LOBBY_USER_LIFECYCLE_STREAM"
|
||||
@@ -69,8 +65,6 @@ const (
|
||||
defaultReadHeaderTimeout = 2 * time.Second
|
||||
defaultReadTimeout = 10 * time.Second
|
||||
defaultIdleTimeout = time.Minute
|
||||
defaultRedisDB = 0
|
||||
defaultRedisOperationTimeout = 2 * time.Second
|
||||
defaultGMEventsStream = "gm:lobby_events"
|
||||
defaultGMEventsReadBlockTimeout = 2 * time.Second
|
||||
defaultUserLifecycleStream = "user:lifecycle_events"
|
||||
@@ -86,12 +80,13 @@ const (
|
||||
defaultRaceNameExpirationInterval = time.Hour
|
||||
defaultOTelServiceName = "galaxy-lobby"
|
||||
|
||||
// RaceNameDirectoryBackendRedis selects the Redis-backed Race Name
|
||||
// Directory adapter. It is the default production backend.
|
||||
RaceNameDirectoryBackendRedis = "redis"
|
||||
// RaceNameDirectoryBackendPostgres selects the PostgreSQL-backed
|
||||
// Race Name Directory adapter. It is the default production backend
|
||||
// after PG_PLAN.md §6B.
|
||||
RaceNameDirectoryBackendPostgres = "postgres"
|
||||
|
||||
// RaceNameDirectoryBackendStub selects the in-process Race Name
|
||||
// Directory stub used by unit tests that do not need Redis.
|
||||
// Directory stub used by unit tests that do not need PostgreSQL.
|
||||
RaceNameDirectoryBackendStub = "stub"
|
||||
)
|
||||
|
||||
@@ -115,6 +110,10 @@ type Config struct {
|
||||
// consumed by the runnable service skeleton and its future workers.
|
||||
Redis RedisConfig
|
||||
|
||||
// Postgres configures the PostgreSQL-backed durable store consumed via
|
||||
// `pkg/postgres`.
|
||||
Postgres PostgresConfig
|
||||
|
||||
// UserService configures the synchronous User Service eligibility client.
|
||||
UserService UserServiceConfig
|
||||
|
||||
@@ -143,7 +142,7 @@ type Config struct {
|
||||
// is wired into the runtime.
|
||||
type RaceNameDirectoryConfig struct {
|
||||
// Backend selects the Race Name Directory adapter. Accepted values
|
||||
// are RaceNameDirectoryBackendRedis and RaceNameDirectoryBackendStub.
|
||||
// are RaceNameDirectoryBackendPostgres and RaceNameDirectoryBackendStub.
|
||||
Backend string
|
||||
}
|
||||
|
||||
@@ -151,14 +150,14 @@ type RaceNameDirectoryConfig struct {
|
||||
// backend selector.
|
||||
func (cfg RaceNameDirectoryConfig) Validate() error {
|
||||
switch cfg.Backend {
|
||||
case RaceNameDirectoryBackendRedis, RaceNameDirectoryBackendStub:
|
||||
case RaceNameDirectoryBackendPostgres, RaceNameDirectoryBackendStub:
|
||||
return nil
|
||||
case "":
|
||||
return fmt.Errorf("race name directory backend must not be empty")
|
||||
default:
|
||||
return fmt.Errorf("race name directory backend %q must be one of %q or %q",
|
||||
cfg.Backend,
|
||||
RaceNameDirectoryBackendRedis,
|
||||
RaceNameDirectoryBackendPostgres,
|
||||
RaceNameDirectoryBackendStub)
|
||||
}
|
||||
}
|
||||
@@ -237,26 +236,15 @@ func (cfg InternalHTTPConfig) Validate() error {
|
||||
}
|
||||
}
|
||||
|
||||
// RedisConfig configures the shared Redis client and the Redis-owned
|
||||
// Streams keys consumed by the runnable service skeleton.
|
||||
// RedisConfig configures the Game Lobby Redis connection topology and the
|
||||
// Redis Stream names Lobby reads from / writes to. Per-call timeouts and
|
||||
// connection topology live inside `Conn`.
|
||||
type RedisConfig struct {
|
||||
// Addr stores the Redis network address.
|
||||
Addr string
|
||||
|
||||
// Username stores the optional Redis ACL username.
|
||||
Username string
|
||||
|
||||
// Password stores the optional Redis ACL password.
|
||||
Password string
|
||||
|
||||
// DB stores the Redis logical database index.
|
||||
DB int
|
||||
|
||||
// TLSEnabled reports whether TLS must be used for Redis connections.
|
||||
TLSEnabled bool
|
||||
|
||||
// OperationTimeout bounds one Redis round trip including the startup PING.
|
||||
OperationTimeout time.Duration
|
||||
// Conn carries the connection topology (master, replicas, password, db,
|
||||
// per-call timeout). Loaded via redisconn.LoadFromEnv("LOBBY"); rejects
|
||||
// the deprecated LOBBY_REDIS_TLS_ENABLED / LOBBY_REDIS_USERNAME env vars
|
||||
// at startup.
|
||||
Conn redisconn.Config
|
||||
|
||||
// GMEventsStream stores the Redis Streams key for Game Master runtime
|
||||
// events consumed by Lobby.
|
||||
@@ -297,27 +285,12 @@ type RedisConfig struct {
|
||||
UserLifecycleReadBlockTimeout time.Duration
|
||||
}
|
||||
|
||||
// TLSConfig returns the conservative TLS configuration used by the Redis
|
||||
// client when TLSEnabled is true.
|
||||
func (cfg RedisConfig) TLSConfig() *tls.Config {
|
||||
if !cfg.TLSEnabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &tls.Config{MinVersion: tls.VersionTLS12}
|
||||
}
|
||||
|
||||
// Validate reports whether cfg stores a usable Redis configuration.
|
||||
func (cfg RedisConfig) Validate() error {
|
||||
if err := cfg.Conn.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
switch {
|
||||
case strings.TrimSpace(cfg.Addr) == "":
|
||||
return fmt.Errorf("redis addr must not be empty")
|
||||
case !isTCPAddr(cfg.Addr):
|
||||
return fmt.Errorf("redis addr %q must use host:port form", cfg.Addr)
|
||||
case cfg.DB < 0:
|
||||
return fmt.Errorf("redis db must not be negative")
|
||||
case cfg.OperationTimeout <= 0:
|
||||
return fmt.Errorf("redis operation timeout must be positive")
|
||||
case strings.TrimSpace(cfg.GMEventsStream) == "":
|
||||
return fmt.Errorf("redis gm events stream must not be empty")
|
||||
case cfg.GMEventsReadBlockTimeout <= 0:
|
||||
@@ -341,6 +314,19 @@ func (cfg RedisConfig) Validate() error {
|
||||
}
|
||||
}
|
||||
|
||||
// PostgresConfig configures the PostgreSQL-backed durable store consumed via
|
||||
// `pkg/postgres`. Topology and pool tuning live in `Conn`; loaded via
|
||||
// `postgres.LoadFromEnv("LOBBY")`.
|
||||
type PostgresConfig struct {
|
||||
// Conn carries the primary plus replica DSN topology and pool tuning.
|
||||
Conn postgres.Config
|
||||
}
|
||||
|
||||
// Validate reports whether cfg stores a usable PostgreSQL configuration.
|
||||
func (cfg PostgresConfig) Validate() error {
|
||||
return cfg.Conn.Validate()
|
||||
}
|
||||
|
||||
// UserServiceConfig configures the synchronous User Service eligibility
|
||||
// client used by the application flow.
|
||||
type UserServiceConfig struct {
|
||||
@@ -489,8 +475,7 @@ func DefaultConfig() Config {
|
||||
IdleTimeout: defaultIdleTimeout,
|
||||
},
|
||||
Redis: RedisConfig{
|
||||
DB: defaultRedisDB,
|
||||
OperationTimeout: defaultRedisOperationTimeout,
|
||||
Conn: redisconn.DefaultConfig(),
|
||||
GMEventsStream: defaultGMEventsStream,
|
||||
GMEventsReadBlockTimeout: defaultGMEventsReadBlockTimeout,
|
||||
RuntimeStartJobsStream: defaultRuntimeStartJobsStream,
|
||||
@@ -501,6 +486,9 @@ func DefaultConfig() Config {
|
||||
UserLifecycleStream: defaultUserLifecycleStream,
|
||||
UserLifecycleReadBlockTimeout: defaultUserLifecycleReadBlockTimeout,
|
||||
},
|
||||
Postgres: PostgresConfig{
|
||||
Conn: postgres.DefaultConfig(),
|
||||
},
|
||||
UserService: UserServiceConfig{
|
||||
Timeout: defaultUserServiceTimeout,
|
||||
},
|
||||
@@ -511,7 +499,7 @@ func DefaultConfig() Config {
|
||||
Interval: defaultEnrollmentAutomationInterval,
|
||||
},
|
||||
RaceNameDirectory: RaceNameDirectoryConfig{
|
||||
Backend: RaceNameDirectoryBackendRedis,
|
||||
Backend: RaceNameDirectoryBackendPostgres,
|
||||
},
|
||||
PendingRegistration: PendingRegistrationConfig{
|
||||
Interval: defaultRaceNameExpirationInterval,
|
||||
|
||||
Reference in New Issue
Block a user