redis

package
v10.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 15, 2026 License: AGPL-3.0 Imports: 20 Imported by: 0

Documentation

Overview

Package redis is a messagequeue publisher and consumer over Redis pub/sub.

This is pub/sub, not Redis Streams, and the difference is the whole of what choosing it commits a caller to.

At-most-once, with no way to notice

Nothing is persisted. A message published while no consumer is subscribed is gone — Redis does not buffer for a subscriber that has not arrived yet, and there is no backlog to read on connect. A handler that returns an error does not see the message again; the error is reported on the consumer's error channel and the loop moves to the next message. There is no acknowledgement, no redelivery, and no dead-letter path, because pub/sub has none to expose.

Work that must not be lost belongs on kafka, pubsub, or sqs, all three of which are at-least-once. What redis is for is fanout where a missed message is tolerable and a broker nobody has to operate is worth more than the guarantee: cache invalidation, presence, live counters.

The one loss this package does close is the subscription race. NewConsumer blocks for a round trip until Redis confirms the SUBSCRIBE has been registered server-side, so a publisher racing a starting consumer cannot slip a message into the window between "we asked to subscribe" and "the server agreed".

Fanout, not work distribution

Every subscriber on a channel receives every message. Two replicas of a service consuming the same topic both run the handler for each message, which is the opposite of what a consumer group does. There is no partitioning and no ordering guarantee beyond what a single Redis connection happens to deliver.

This is why the publisher accepts every messagequeue.PublishOption and honors none. There is nothing here for an ordering key to name — no partitions, no groups, no per-key sequencing — and nothing that deduplicates, so a key given to this publisher changes nothing. It is accepted rather than rejected so that a caller can pass the same options to whichever publisher it was wired with, but a caller who needs ordering needs kafka, pubsub or sqs, not a different call.

Lifecycle

Both providers validate their config at construction and build the client there, so an address list Redis cannot use is a startup error rather than a nil client that panics on first publish. A publisher's Stop is a no-op — the client is shared across every topic, and the provider's Close is what releases it. Consumers close their own subscriptions when their Consume loop exits.

One consumer per topic per provider: a second NewConsumer for the same topic returns messagequeue.ErrConsumerAlreadyRegistered rather than handing back the first caller's consumer wired to the first caller's handler.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	Username       string   `env:"USERNAME"        json:"username,omitempty"       yaml:"username,omitempty"`
	Password       string   `env:"PASSWORD"        json:"password,omitempty"       yaml:"password,omitempty"`
	QueueAddresses []string `env:"QUEUE_ADDRESSES" json:"queueAddresses,omitempty" yaml:"queueAddresses,omitempty"`
}

Config configures a Redis-backed consumer.

func (*Config) ValidateWithContext

func (cfg *Config) ValidateWithContext(ctx context.Context) error

ValidateWithContext validates a Config struct.

type ConsumerProvider

type ConsumerProvider struct {
	// contains filtered or unexported fields
}

ConsumerProvider is the Redis messagequeue.ConsumerProvider implementation. It is exported, and returned by NewRedisConsumerProvider, so a caller who has chosen Redis can depend on that choice rather than on the interface every broker shares.

func NewRedisConsumerProvider

func NewRedisConsumerProvider(ctx context.Context, cfg Config, opts ...Option) (*ConsumerProvider, error)

NewRedisConsumerProvider returns a ConsumerProvider for a given address.

It takes a context and reports an error so that the config's own ValidateWithContext runs here, and so that an address list redisclient refuses is a startup error. Without either, a config naming no QueueAddresses built cleanly and the provider came back holding a nil client — which nothing noticed until the first Ping panicked.

func (*ConsumerProvider) Close

func (p *ConsumerProvider) Close()

Close closes the shared Redis client, mirroring the publisher provider. Cached consumers close their own subscriptions when their Consume loops exit.

func (*ConsumerProvider) NewConsumer

func (p *ConsumerProvider) NewConsumer(ctx context.Context, topic string, handlerFunc messagequeue.ConsumerFunc) (messagequeue.Consumer, error)

NewConsumer returns a Consumer for a given topic.

type Option

type Option func(*options)

Option configures the providers this package constructs. The zero configuration works: absent observability deps are normalized downstream.

func WithLogger

func WithLogger(logger logging.Logger) Option

WithLogger attaches a logger.

func WithMetricsProvider

func WithMetricsProvider(metricsProvider metrics.Provider) Option

WithMetricsProvider attaches a metrics provider.

func WithTracerProvider

func WithTracerProvider(tracerProvider tracing.Provider) Option

WithTracerProvider attaches a tracer provider.

type PublisherProvider

type PublisherProvider struct {
	// contains filtered or unexported fields
}

PublisherProvider is the Redis messagequeue.PublisherProvider implementation. It is exported, and returned by NewRedisPublisherProvider, so a caller who has chosen Redis can depend on that choice rather than on the interface every broker shares.

func NewRedisPublisherProvider

func NewRedisPublisherProvider(ctx context.Context, cfg Config, opts ...Option) (*PublisherProvider, error)

NewRedisPublisherProvider returns a PublisherProvider for a given address.

It takes a context and reports an error so that the config's own ValidateWithContext runs here, and so that an address list redisclient refuses is a startup error. Without either, a config naming no QueueAddresses built cleanly and the provider came back holding a nil client — which nothing noticed until the first Publish panicked, in whichever goroutine happened to make it.

func (*PublisherProvider) Close

func (p *PublisherProvider) Close()

Close closes the publisher.

func (*PublisherProvider) NewPublisher

func (p *PublisherProvider) NewPublisher(ctx context.Context, topic string) (messagequeue.Publisher, error)

NewPublisher returns a Publisher for a given topic.

func (*PublisherProvider) Ping

func (p *PublisherProvider) Ping(ctx context.Context) error

Ping pings the underlying Redis client.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL