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
+27 -60
View File
@@ -7,6 +7,7 @@ import (
"galaxy/authsession/internal/adapters/local"
"galaxy/authsession/internal/adapters/mail"
redisadapter "galaxy/authsession/internal/adapters/redis"
"galaxy/authsession/internal/adapters/redis/challengestore"
"galaxy/authsession/internal/adapters/redis/configprovider"
"galaxy/authsession/internal/adapters/redis/projectionpublisher"
@@ -26,17 +27,10 @@ import (
"galaxy/authsession/internal/service/sendemailcode"
"galaxy/authsession/internal/telemetry"
"github.com/redis/go-redis/v9"
"go.uber.org/zap"
)
type pinger interface {
Ping(context.Context) error
}
type closer interface {
Close() error
}
// Runtime owns the runnable authsession application plus the adapter cleanup
// functions that must run after the process stops.
type Runtime struct {
@@ -65,91 +59,64 @@ func NewRuntime(ctx context.Context, cfg config.Config, logger *zap.Logger, tele
return nil, errors.Join(err, runtime.Close())
}
challengeStore, err := challengestore.New(challengestore.Config{
Addr: cfg.Redis.Addr,
Username: cfg.Redis.Username,
Password: cfg.Redis.Password,
DB: cfg.Redis.DB,
TLSEnabled: cfg.Redis.TLSEnabled,
redisClient := redisadapter.NewClient(cfg.Redis)
if err := redisadapter.InstrumentClient(redisClient, telemetryRuntime); err != nil {
return cleanupOnError(fmt.Errorf("new authsession runtime: %w", err))
}
runtime.cleanupFns = append(runtime.cleanupFns, func() error {
err := redisClient.Close()
if errors.Is(err, redis.ErrClosed) {
return nil
}
return err
})
if err := redisadapter.Ping(ctx, cfg.Redis, redisClient); err != nil {
return cleanupOnError(fmt.Errorf("new authsession runtime: %w", err))
}
challengeStore, err := challengestore.New(redisClient, challengestore.Config{
KeyPrefix: cfg.Redis.ChallengeKeyPrefix,
OperationTimeout: cfg.Redis.OperationTimeout,
OperationTimeout: cfg.Redis.Conn.OperationTimeout,
})
if err != nil {
return cleanupOnError(fmt.Errorf("new authsession runtime: challenge store: %w", err))
}
runtime.cleanupFns = append(runtime.cleanupFns, challengeStore.Close)
sessionStore, err := sessionstore.New(sessionstore.Config{
Addr: cfg.Redis.Addr,
Username: cfg.Redis.Username,
Password: cfg.Redis.Password,
DB: cfg.Redis.DB,
TLSEnabled: cfg.Redis.TLSEnabled,
sessionStore, err := sessionstore.New(redisClient, sessionstore.Config{
SessionKeyPrefix: cfg.Redis.SessionKeyPrefix,
UserSessionsKeyPrefix: cfg.Redis.UserSessionsKeyPrefix,
UserActiveSessionsKeyPrefix: cfg.Redis.UserActiveSessionsKeyPrefix,
OperationTimeout: cfg.Redis.OperationTimeout,
OperationTimeout: cfg.Redis.Conn.OperationTimeout,
})
if err != nil {
return cleanupOnError(fmt.Errorf("new authsession runtime: session store: %w", err))
}
runtime.cleanupFns = append(runtime.cleanupFns, sessionStore.Close)
configStore, err := configprovider.New(configprovider.Config{
Addr: cfg.Redis.Addr,
Username: cfg.Redis.Username,
Password: cfg.Redis.Password,
DB: cfg.Redis.DB,
TLSEnabled: cfg.Redis.TLSEnabled,
configStore, err := configprovider.New(redisClient, configprovider.Config{
SessionLimitKey: cfg.Redis.SessionLimitKey,
OperationTimeout: cfg.Redis.OperationTimeout,
OperationTimeout: cfg.Redis.Conn.OperationTimeout,
})
if err != nil {
return cleanupOnError(fmt.Errorf("new authsession runtime: config provider: %w", err))
}
runtime.cleanupFns = append(runtime.cleanupFns, configStore.Close)
publisher, err := projectionpublisher.New(projectionpublisher.Config{
Addr: cfg.Redis.Addr,
Username: cfg.Redis.Username,
Password: cfg.Redis.Password,
DB: cfg.Redis.DB,
TLSEnabled: cfg.Redis.TLSEnabled,
publisher, err := projectionpublisher.New(redisClient, projectionpublisher.Config{
SessionCacheKeyPrefix: cfg.Redis.GatewaySessionCacheKeyPrefix,
SessionEventsStream: cfg.Redis.GatewaySessionEventsStream,
StreamMaxLen: cfg.Redis.GatewaySessionEventsStreamMaxLen,
OperationTimeout: cfg.Redis.OperationTimeout,
OperationTimeout: cfg.Redis.Conn.OperationTimeout,
})
if err != nil {
return cleanupOnError(fmt.Errorf("new authsession runtime: projection publisher: %w", err))
}
runtime.cleanupFns = append(runtime.cleanupFns, publisher.Close)
abuseProtector, err := sendemailcodeabuse.New(sendemailcodeabuse.Config{
Addr: cfg.Redis.Addr,
Username: cfg.Redis.Username,
Password: cfg.Redis.Password,
DB: cfg.Redis.DB,
TLSEnabled: cfg.Redis.TLSEnabled,
abuseProtector, err := sendemailcodeabuse.New(redisClient, sendemailcodeabuse.Config{
KeyPrefix: cfg.Redis.SendEmailCodeThrottleKeyPrefix,
OperationTimeout: cfg.Redis.OperationTimeout,
OperationTimeout: cfg.Redis.Conn.OperationTimeout,
})
if err != nil {
return cleanupOnError(fmt.Errorf("new authsession runtime: send email code abuse protector: %w", err))
}
runtime.cleanupFns = append(runtime.cleanupFns, abuseProtector.Close)
for name, dependency := range map[string]pinger{
"challenge store": challengeStore,
"session store": sessionStore,
"config provider": configStore,
"projection publisher": publisher,
"send email code abuse protector": abuseProtector,
} {
if err := dependency.Ping(ctx); err != nil {
return cleanupOnError(fmt.Errorf("new authsession runtime: ping %s: %w", name, err))
}
}
clock := local.Clock{}
idGenerator := local.IDGenerator{}
+9 -5
View File
@@ -26,7 +26,8 @@ func TestNewRuntimeStartsAndStopsHTTPServers(t *testing.T) {
redisServer := miniredis.RunT(t)
cfg := config.DefaultConfig()
cfg.Redis.Addr = redisServer.Addr()
cfg.Redis.Conn.MasterAddr = redisServer.Addr()
cfg.Redis.Conn.Password = "integration"
cfg.PublicHTTP.Addr = mustFreeAddr(t)
cfg.InternalHTTP.Addr = mustFreeAddr(t)
cfg.ShutdownTimeout = 10 * time.Second
@@ -69,7 +70,8 @@ func TestNewRuntimeUsesRESTUserDirectoryWhenConfigured(t *testing.T) {
defer userService.Close()
cfg := config.DefaultConfig()
cfg.Redis.Addr = redisServer.Addr()
cfg.Redis.Conn.MasterAddr = redisServer.Addr()
cfg.Redis.Conn.Password = "integration"
cfg.PublicHTTP.Addr = mustFreeAddr(t)
cfg.InternalHTTP.Addr = mustFreeAddr(t)
cfg.UserService.Mode = "rest"
@@ -116,7 +118,8 @@ func TestNewRuntimeUsesRESTMailSenderWhenConfigured(t *testing.T) {
defer mailService.Close()
cfg := config.DefaultConfig()
cfg.Redis.Addr = redisServer.Addr()
cfg.Redis.Conn.MasterAddr = redisServer.Addr()
cfg.Redis.Conn.Password = "integration"
cfg.PublicHTTP.Addr = mustFreeAddr(t)
cfg.InternalHTTP.Addr = mustFreeAddr(t)
cfg.MailService.Mode = "rest"
@@ -152,12 +155,13 @@ func TestNewRuntimeFailsFastWhenRedisPingChecksFail(t *testing.T) {
t.Parallel()
cfg := config.DefaultConfig()
cfg.Redis.Addr = mustFreeAddr(t)
cfg.Redis.Conn.MasterAddr = mustFreeAddr(t)
cfg.Redis.Conn.Password = "integration"
runtime, err := NewRuntime(context.Background(), cfg, zap.NewNop(), nil)
require.Nil(t, runtime)
require.Error(t, err)
assert.ErrorContains(t, err, "new authsession runtime: ping")
assert.ErrorContains(t, err, "ping redis")
}
func mustFreeAddr(t *testing.T) string {