channel_cache.go 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. package repository
  2. import (
  3. "context"
  4. "log/slog"
  5. "github.com/Wei-Shaw/sub2api/internal/service"
  6. "github.com/redis/go-redis/v9"
  7. )
  8. const channelCachePubSubKey = "channel_cache_updated"
  9. type channelCache struct {
  10. rdb *redis.Client
  11. }
  12. // NewChannelCache creates the Redis-backed channel cache invalidation bus.
  13. func NewChannelCache(rdb *redis.Client) service.ChannelCachePubSub {
  14. return &channelCache{rdb: rdb}
  15. }
  16. // NotifyUpdate notifies all instances to invalidate their local channel cache.
  17. func (c *channelCache) NotifyUpdate(ctx context.Context) error {
  18. return c.rdb.Publish(ctx, channelCachePubSubKey, "refresh").Err()
  19. }
  20. // SubscribeUpdates subscribes to channel cache invalidation notifications.
  21. func (c *channelCache) SubscribeUpdates(ctx context.Context, handler func()) {
  22. go func() {
  23. pubsub := c.rdb.Subscribe(ctx, channelCachePubSubKey)
  24. defer func() {
  25. if err := pubsub.Close(); err != nil {
  26. slog.Warn("failed to close channel cache subscriber", "error", err)
  27. }
  28. }()
  29. messages := pubsub.Channel()
  30. for {
  31. select {
  32. case <-ctx.Done():
  33. return
  34. case message, ok := <-messages:
  35. if !ok {
  36. slog.Warn("channel cache subscriber stopped", "reason", "channel_closed")
  37. return
  38. }
  39. if message != nil {
  40. handler()
  41. }
  42. }
  43. }
  44. }()
  45. }