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
@@ -4,7 +4,6 @@ package domainevents
import (
"context"
"crypto/tls"
"errors"
"fmt"
"strconv"
@@ -17,23 +16,11 @@ import (
"go.opentelemetry.io/otel/trace"
)
// Config configures one Redis-backed user domain-event publisher.
// Config configures one Redis-backed user domain-event publisher. The
// connection is supplied externally by the runtime so multiple publishers
// can share one *redis.Client; this struct now carries only stream-shape
// parameters.
type Config struct {
// Addr is the Redis network address in host:port form.
Addr string
// Username is the optional Redis ACL username.
Username string
// Password is the optional Redis ACL password.
Password string
// DB is the Redis logical database index.
DB int
// TLSEnabled enables TLS with a conservative minimum protocol version.
TLSEnabled bool
// Stream identifies the Redis Stream key used for domain events.
Stream string
@@ -53,13 +40,13 @@ type Publisher struct {
operationTimeout time.Duration
}
// New constructs a Redis-backed domain-event publisher from cfg.
func New(cfg Config) (*Publisher, error) {
// New constructs a Redis-backed domain-event publisher backed by the
// supplied client. The publisher does not own the client; the runtime is
// responsible for closing it.
func New(client *redis.Client, cfg Config) (*Publisher, error) {
switch {
case strings.TrimSpace(cfg.Addr) == "":
return nil, errors.New("new redis domain-event publisher: redis addr must not be empty")
case cfg.DB < 0:
return nil, errors.New("new redis domain-event publisher: redis db must not be negative")
case client == nil:
return nil, errors.New("new redis domain-event publisher: redis client must not be nil")
case strings.TrimSpace(cfg.Stream) == "":
return nil, errors.New("new redis domain-event publisher: stream must not be empty")
case cfg.StreamMaxLen <= 0:
@@ -68,33 +55,19 @@ func New(cfg Config) (*Publisher, error) {
return nil, errors.New("new redis domain-event publisher: operation timeout must be positive")
}
options := &redis.Options{
Addr: cfg.Addr,
Username: cfg.Username,
Password: cfg.Password,
DB: cfg.DB,
Protocol: 2,
DisableIdentity: true,
}
if cfg.TLSEnabled {
options.TLSConfig = &tls.Config{MinVersion: tls.VersionTLS12}
}
return &Publisher{
client: redis.NewClient(options),
client: client,
stream: cfg.Stream,
streamMaxLen: cfg.StreamMaxLen,
operationTimeout: cfg.OperationTimeout,
}, nil
}
// Close releases the underlying Redis client resources.
// Close is a no-op: the client is owned by the runtime, not the publisher.
// The accessor remains for API symmetry with the previous Redis adapter so
// runtime cleanup chains do not need to special-case this surface.
func (publisher *Publisher) Close() error {
if publisher == nil || publisher.client == nil {
return nil
}
return publisher.client.Close()
return nil
}
// Ping verifies that the configured Redis backend is reachable within the
@@ -10,6 +10,7 @@ import (
"galaxy/user/internal/ports"
"github.com/alicebob/miniredis/v2"
"github.com/redis/go-redis/v9"
"github.com/stretchr/testify/require"
)
@@ -17,8 +18,7 @@ func TestPublisherPublishesFlatRedisStreamEntry(t *testing.T) {
t.Parallel()
server := miniredis.RunT(t)
publisher, err := New(Config{
Addr: server.Addr(),
publisher, err := New(redis.NewClient(&redis.Options{Addr: server.Addr()}), Config{
Stream: "user:test_events",
StreamMaxLen: 5,
OperationTimeout: time.Second,
@@ -70,8 +70,7 @@ func TestPublisherRejectsInvalidEventBeforeXAdd(t *testing.T) {
t.Parallel()
server := miniredis.RunT(t)
publisher, err := New(Config{
Addr: server.Addr(),
publisher, err := New(redis.NewClient(&redis.Options{Addr: server.Addr()}), Config{
Stream: "user:test_events",
StreamMaxLen: 5,
OperationTimeout: time.Second,