feat: use postgres

This commit is contained in:
Ilia Denisov
2026-04-26 20:34:39 +02:00
committed by GitHub
parent 48b0056b49
commit fe829285a6
365 changed files with 29223 additions and 24049 deletions
+42 -69
View File
@@ -18,11 +18,13 @@ import (
"galaxy/gateway/internal/grpcapi"
"galaxy/gateway/internal/logging"
"galaxy/gateway/internal/push"
"galaxy/gateway/internal/redisclient"
"galaxy/gateway/internal/replay"
"galaxy/gateway/internal/restapi"
"galaxy/gateway/internal/session"
"galaxy/gateway/internal/telemetry"
"github.com/redis/go-redis/v9"
"go.uber.org/zap"
)
@@ -132,112 +134,83 @@ func newAuthenticatedGRPCDependencies(ctx context.Context, cfg config.Config, lo
return grpcapi.ServerDependencies{}, nil, nil, fmt.Errorf("build authenticated grpc dependencies: load response signer: %w", err)
}
fallbackSessionCache, err := session.NewRedisCache(cfg.SessionCacheRedis)
if err != nil {
return grpcapi.ServerDependencies{}, nil, nil, fmt.Errorf("build authenticated grpc dependencies: %w", err)
}
replayStore, err := replay.NewRedisStore(cfg.SessionCacheRedis, cfg.ReplayRedis)
if err != nil {
closeErr := fallbackSessionCache.Close()
redisClient := redisclient.NewClient(cfg.Redis)
if err := redisclient.InstrumentClient(redisClient, telemetryRuntime); err != nil {
closeErr := redisClient.Close()
return grpcapi.ServerDependencies{}, nil, nil, errors.Join(
fmt.Errorf("build authenticated grpc dependencies: %w", err),
closeErr,
)
}
closeRedisClient := func() error {
err := redisClient.Close()
if errors.Is(err, redis.ErrClosed) {
return nil
}
return err
}
if err := redisclient.Ping(ctx, cfg.Redis, redisClient); err != nil {
closeErr := closeRedisClient()
return grpcapi.ServerDependencies{}, nil, nil, errors.Join(
fmt.Errorf("build authenticated grpc dependencies: %w", err),
closeErr,
)
}
fallbackSessionCache, err := session.NewRedisCache(redisClient, cfg.SessionCacheRedis)
if err != nil {
return grpcapi.ServerDependencies{}, nil, nil, errors.Join(
fmt.Errorf("build authenticated grpc dependencies: %w", err),
closeRedisClient(),
)
}
replayStore, err := replay.NewRedisStore(redisClient, cfg.ReplayRedis)
if err != nil {
return grpcapi.ServerDependencies{}, nil, nil, errors.Join(
fmt.Errorf("build authenticated grpc dependencies: %w", err),
closeRedisClient(),
)
}
localSessionCache := session.NewMemoryCache()
sessionCache, err := session.NewReadThroughCache(localSessionCache, fallbackSessionCache)
if err != nil {
closeErr := errors.Join(
fallbackSessionCache.Close(),
replayStore.Close(),
)
return grpcapi.ServerDependencies{}, nil, nil, errors.Join(
fmt.Errorf("build authenticated grpc dependencies: %w", err),
closeErr,
closeRedisClient(),
)
}
pushHub := push.NewHubWithObserver(0, telemetry.NewPushObserver(telemetryRuntime))
sessionSubscriber, err := events.NewRedisSessionSubscriberWithObservability(cfg.SessionCacheRedis, cfg.SessionEventsRedis, localSessionCache, pushHub, logger, telemetryRuntime)
sessionSubscriber, err := events.NewRedisSessionSubscriberWithObservability(redisClient, cfg.SessionCacheRedis, cfg.SessionEventsRedis, localSessionCache, pushHub, logger, telemetryRuntime)
if err != nil {
closeErr := errors.Join(
fallbackSessionCache.Close(),
replayStore.Close(),
)
return grpcapi.ServerDependencies{}, nil, nil, errors.Join(
fmt.Errorf("build authenticated grpc dependencies: %w", err),
closeErr,
closeRedisClient(),
)
}
clientEventSubscriber, err := events.NewRedisClientEventSubscriberWithObservability(cfg.SessionCacheRedis, cfg.ClientEventsRedis, pushHub, logger, telemetryRuntime)
clientEventSubscriber, err := events.NewRedisClientEventSubscriberWithObservability(redisClient, cfg.SessionCacheRedis, cfg.ClientEventsRedis, pushHub, logger, telemetryRuntime)
if err != nil {
closeErr := errors.Join(
fallbackSessionCache.Close(),
replayStore.Close(),
sessionSubscriber.Close(),
)
return grpcapi.ServerDependencies{}, nil, nil, errors.Join(
fmt.Errorf("build authenticated grpc dependencies: %w", err),
closeErr,
closeRedisClient(),
)
}
userRoutes, closeUserServiceRoutes, err := userservice.NewRoutes(cfg.UserService.BaseURL)
if err != nil {
closeErr := errors.Join(
fallbackSessionCache.Close(),
replayStore.Close(),
sessionSubscriber.Close(),
clientEventSubscriber.Close(),
)
return grpcapi.ServerDependencies{}, nil, nil, errors.Join(
fmt.Errorf("build authenticated grpc dependencies: user service routes: %w", err),
closeErr,
closeRedisClient(),
)
}
cleanup := func() error {
return errors.Join(
fallbackSessionCache.Close(),
replayStore.Close(),
sessionSubscriber.Close(),
clientEventSubscriber.Close(),
closeUserServiceRoutes(),
)
}
if err := fallbackSessionCache.Ping(ctx); err != nil {
closeErr := cleanup()
return grpcapi.ServerDependencies{}, nil, nil, errors.Join(
fmt.Errorf("build authenticated grpc dependencies: %w", err),
closeErr,
)
}
if err := replayStore.Ping(ctx); err != nil {
closeErr := cleanup()
return grpcapi.ServerDependencies{}, nil, nil, errors.Join(
fmt.Errorf("build authenticated grpc dependencies: %w", err),
closeErr,
)
}
if err := sessionSubscriber.Ping(ctx); err != nil {
closeErr := cleanup()
return grpcapi.ServerDependencies{}, nil, nil, errors.Join(
fmt.Errorf("build authenticated grpc dependencies: %w", err),
closeErr,
)
}
if err := clientEventSubscriber.Ping(ctx); err != nil {
closeErr := cleanup()
return grpcapi.ServerDependencies{}, nil, nil, errors.Join(
fmt.Errorf("build authenticated grpc dependencies: %w", err),
closeErr,
closeRedisClient(),
)
}
+21 -9
View File
@@ -15,6 +15,7 @@ import (
"galaxy/gateway/internal/config"
"galaxy/gateway/internal/restapi"
"galaxy/redisconn"
"github.com/alicebob/miniredis/v2"
"github.com/stretchr/testify/assert"
@@ -22,6 +23,16 @@ import (
"go.uber.org/zap"
)
func testRedisConn(masterAddr string, opTimeout time.Duration) redisconn.Config {
cfg := redisconn.DefaultConfig()
cfg.MasterAddr = masterAddr
cfg.Password = "integration"
if opTimeout > 0 {
cfg.OperationTimeout = opTimeout
}
return cfg
}
func TestNewPublicRESTDependencies(t *testing.T) {
t.Parallel()
@@ -102,8 +113,8 @@ func TestNewAuthenticatedGRPCDependencies(t *testing.T) {
{
name: "success",
cfg: config.Config{
Redis: testRedisConn(server.Addr(), 250*time.Millisecond),
SessionCacheRedis: config.SessionCacheRedisConfig{
Addr: server.Addr(),
KeyPrefix: "gateway:session:",
LookupTimeout: 250 * time.Millisecond,
},
@@ -125,8 +136,9 @@ func TestNewAuthenticatedGRPCDependencies(t *testing.T) {
},
},
{
name: "invalid redis config",
name: "invalid session cache key prefix",
cfg: config.Config{
Redis: testRedisConn(server.Addr(), 250*time.Millisecond),
SessionCacheRedis: config.SessionCacheRedisConfig{
LookupTimeout: 250 * time.Millisecond,
},
@@ -146,13 +158,13 @@ func TestNewAuthenticatedGRPCDependencies(t *testing.T) {
PrivateKeyPEMPath: responseSignerPEMPath,
},
},
wantErr: "redis addr must not be empty",
wantErr: "redis key prefix must not be empty",
},
{
name: "startup ping failure",
cfg: config.Config{
Redis: testRedisConn(unusedTCPAddr(t), 100*time.Millisecond),
SessionCacheRedis: config.SessionCacheRedisConfig{
Addr: unusedTCPAddr(t),
KeyPrefix: "gateway:session:",
LookupTimeout: 100 * time.Millisecond,
},
@@ -172,13 +184,13 @@ func TestNewAuthenticatedGRPCDependencies(t *testing.T) {
PrivateKeyPEMPath: responseSignerPEMPath,
},
},
wantErr: "ping redis session cache",
wantErr: "ping redis",
},
{
name: "invalid replay config",
cfg: config.Config{
Redis: testRedisConn(server.Addr(), 250*time.Millisecond),
SessionCacheRedis: config.SessionCacheRedisConfig{
Addr: server.Addr(),
KeyPrefix: "gateway:session:",
LookupTimeout: 250 * time.Millisecond,
},
@@ -202,8 +214,8 @@ func TestNewAuthenticatedGRPCDependencies(t *testing.T) {
{
name: "invalid client event config",
cfg: config.Config{
Redis: testRedisConn(server.Addr(), 250*time.Millisecond),
SessionCacheRedis: config.SessionCacheRedisConfig{
Addr: server.Addr(),
KeyPrefix: "gateway:session:",
LookupTimeout: 250 * time.Millisecond,
},
@@ -227,8 +239,8 @@ func TestNewAuthenticatedGRPCDependencies(t *testing.T) {
{
name: "missing response signer path",
cfg: config.Config{
Redis: testRedisConn(server.Addr(), 250*time.Millisecond),
SessionCacheRedis: config.SessionCacheRedisConfig{
Addr: server.Addr(),
KeyPrefix: "gateway:session:",
LookupTimeout: 250 * time.Millisecond,
},
@@ -250,8 +262,8 @@ func TestNewAuthenticatedGRPCDependencies(t *testing.T) {
{
name: "invalid response signer pem",
cfg: config.Config{
Redis: testRedisConn(server.Addr(), 250*time.Millisecond),
SessionCacheRedis: config.SessionCacheRedisConfig{
Addr: server.Addr(),
KeyPrefix: "gateway:session:",
LookupTimeout: 250 * time.Millisecond,
},