Files
galaxy-game/notification/internal/adapters/postgres/routepublisher/store.go
T
2026-04-26 20:34:39 +02:00

87 lines
3.7 KiB
Go

// Package routepublisher composes one PostgreSQL-backed route-state store
// (notificationstore) with one Redis-backed lease store (redisstate.LeaseStore)
// behind the publisher worker contracts. The composition lets push and email
// publishers keep their existing one-store dependency while Stage 5 of
// `PG_PLAN.md` splits durable state to PostgreSQL and the short-lived
// per-replica exclusivity lease to Redis.
package routepublisher
import (
"context"
"errors"
"time"
"galaxy/notification/internal/adapters/postgres/notificationstore"
"galaxy/notification/internal/adapters/redisstate"
"galaxy/notification/internal/service/acceptintent"
"galaxy/notification/internal/service/routestate"
"galaxy/notification/internal/telemetry"
)
// Store delegates each route-publisher method to either the durable state
// store (PostgreSQL) or the lease store (Redis), preserving the umbrella
// contract consumed by `worker.PushPublisher` and `worker.EmailPublisher`.
type Store struct {
state *notificationstore.Store
leases *redisstate.LeaseStore
}
// New constructs one composite route-publisher store. Both dependencies are
// required: the SQL store owns route lifecycle and dead-letter persistence,
// and the lease store owns the short-lived per-replica exclusivity hint
// retained on Redis per PG_PLAN.md §5.
func New(state *notificationstore.Store, leases *redisstate.LeaseStore) (*Store, error) {
if state == nil {
return nil, errors.New("new route publisher store: nil notification state store")
}
if leases == nil {
return nil, errors.New("new route publisher store: nil lease store")
}
return &Store{state: state, leases: leases}, nil
}
// ListDueRoutes delegates to the SQL store.
func (store *Store) ListDueRoutes(ctx context.Context, now time.Time, limit int64) ([]routestate.ScheduledRoute, error) {
return store.state.ListDueRoutes(ctx, now, limit)
}
// TryAcquireRouteLease delegates to the Redis lease store.
func (store *Store) TryAcquireRouteLease(ctx context.Context, notificationID string, routeID string, token string, ttl time.Duration) (bool, error) {
return store.leases.TryAcquireRouteLease(ctx, notificationID, routeID, token, ttl)
}
// ReleaseRouteLease delegates to the Redis lease store.
func (store *Store) ReleaseRouteLease(ctx context.Context, notificationID string, routeID string, token string) error {
return store.leases.ReleaseRouteLease(ctx, notificationID, routeID, token)
}
// GetNotification delegates to the SQL store.
func (store *Store) GetNotification(ctx context.Context, notificationID string) (acceptintent.NotificationRecord, bool, error) {
return store.state.GetNotification(ctx, notificationID)
}
// GetRoute delegates to the SQL store.
func (store *Store) GetRoute(ctx context.Context, notificationID string, routeID string) (acceptintent.NotificationRoute, bool, error) {
return store.state.GetRoute(ctx, notificationID, routeID)
}
// CompleteRoutePublished delegates to the SQL store.
func (store *Store) CompleteRoutePublished(ctx context.Context, input routestate.CompleteRoutePublishedInput) error {
return store.state.CompleteRoutePublished(ctx, input)
}
// CompleteRouteFailed delegates to the SQL store.
func (store *Store) CompleteRouteFailed(ctx context.Context, input routestate.CompleteRouteFailedInput) error {
return store.state.CompleteRouteFailed(ctx, input)
}
// CompleteRouteDeadLetter delegates to the SQL store.
func (store *Store) CompleteRouteDeadLetter(ctx context.Context, input routestate.CompleteRouteDeadLetterInput) error {
return store.state.CompleteRouteDeadLetter(ctx, input)
}
// ReadRouteScheduleSnapshot delegates to the SQL store.
func (store *Store) ReadRouteScheduleSnapshot(ctx context.Context) (telemetry.RouteScheduleSnapshot, error) {
return store.state.ReadRouteScheduleSnapshot(ctx)
}