pubsub

package
v0.3.1 Latest Latest
Warning

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

Go to latest
Published: Oct 31, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package pubsub provides typed, ephemeral publication with explicit loss and ownership.

Index

Constants

View Source
const ChannelFeature keyspace.Feature = "pubsub"

ChannelFeature is the physical address family owned by this adapter.

View Source
const MaxSuperviseBackoff = 10 * time.Minute

MaxSuperviseBackoff bounds the delay between re-subscription attempts.

Variables

View Source
var ErrClosed = safeerror.Sentinel(fault.Closed, "pub/sub subscription closed")
View Source
var ErrDisconnected = safeerror.Sentinel(fault.Conflict, "pub/sub subscription disconnected; delivery may have been lost")
View Source
var ErrOverflow = safeerror.Sentinel(fault.Conflict, "pub/sub subscription lost messages because its buffer filled")

Functions

func Module

func Module(name foundation.ProviderID, key foundation.Key[*Broker], config Config, requires []foundation.ProviderID, backend func(foundation.Resolver) (Backend, error)) foundation.Module

Module owns one broker per application. Requires identifies providers owning its borrowed backend, keeping adapters alive until subscriptions have drained.

func ValidatePublish

func ValidatePublish(ctx context.Context, channel Channel, data []byte) error

func ValidateSubscribe

func ValidateSubscribe(ctx context.Context, channels []Channel, limits Limits) error

Types

type Backend

type Backend interface {
	Publish(context.Context, Channel, []byte) (uint64, error)
	Subscribe(context.Context, []Channel, Limits) (Stream, error)
}

Backend exposes ephemeral fan-out, separate from jobs or durable events. Publish returns the authority's subscriber count, not a processing acknowledgement: memory counts subscriptions, Redis counts subscribed connections (one client multiplexes all of its subscriptions over one connection). Subscribe's context bounds establishment only; the returned stream is explicitly owned until Close or adapter shutdown. No implicit publish retry or fallback.

type Broker

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

Broker borrows its adapter and owns callbacks and typed subscriptions. Pure construction performs no I/O. Close cancels work and waits for actual exit.

func NewBroker

func NewBroker(backend Backend, config Config) (*Broker, error)

func (*Broker) Close

func (b *Broker) Close(ctx context.Context) error

Close begins shutdown even when its wait context has expired. Canceled callers can wait again; no resource slot is released before the owned callback exits.

func (*Broker) Done

func (b *Broker) Done() <-chan struct{}

func (*Broker) Namespace

func (b *Broker) Namespace() keyspace.Namespace

func (*Broker) Stats

func (b *Broker) Stats() Stats

type Brokers

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

Brokers is immutable; default and named selection alias the same instance.

func NewBrokers

func NewBrokers(selected ConnectionName, entries ...NamedBroker) (*Brokers, error)

func (*Brokers) Broker

func (r *Brokers) Broker(name ConnectionName) (*Broker, error)

func (*Brokers) Default

func (r *Brokers) Default() (*Broker, error)

func (*Brokers) DefaultName

func (r *Brokers) DefaultName() ConnectionName

func (*Brokers) Names

func (r *Brokers) Names() []ConnectionName

type Channel

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

Channel is an opaque, versioned adapter address. Redis database numbers do not isolate pub/sub; application/environment identity is always part of this address.

func NewChannel

func NewChannel(namespace keyspace.Namespace, name Name, version Version, logical string) (Channel, error)

func (Channel) Namespace

func (c Channel) Namespace() keyspace.Namespace

func (Channel) String

func (c Channel) String() string

func (Channel) Validate

func (c Channel) Validate() error

type Config

type Config struct {
	Namespace                                                     keyspace.Namespace
	MaxDeclarations, MaxKeyBytes, MaxConcurrent, MaxSubscriptions int
	Timeout                                                       time.Duration
	Buffer                                                        Limits
}

Config bounds publication/setup callbacks and separately bounds subscriptions, each of which permits one active receive/decode operation at a time.

func DefaultConfig

func DefaultConfig(namespace keyspace.Namespace) Config

func (Config) Validate

func (c Config) Validate() error

type ConnectionName

type ConnectionName string

ConnectionName selects an instance, distinct from names of other service families.

func (ConnectionName) Validate

func (n ConnectionName) Validate() error

type Declaration

type Declaration[K, V any] struct {
	// contains filtered or unexported fields
}

Declaration preserves both resource-key and JSON payload types. Increment Version for incompatible payload contracts; define once and reuse across callers.

func Define

func Define[K, V any](name Name, version Version, keys keyspace.Codec[K]) Declaration[K, V]

func (Declaration[K, V]) Bind

func (d Declaration[K, V]) Bind(b *Broker) (Topic[K, V], error)

func (Declaration[K, V]) Name

func (d Declaration[K, V]) Name() Name

func (Declaration[K, V]) Validate

func (d Declaration[K, V]) Validate() error

func (Declaration[K, V]) Version

func (d Declaration[K, V]) Version() Version

type Delivery

type Delivery[K, V any] struct {
	Key   K
	Value V
}

Delivery pairs a received payload with the typed key it was published under.

type Gap

type Gap struct {
	Cause    error
	Attempts int
}

Gap reports one interruption after which delivery has resumed. Payloads published between Cause and the new subscription's readiness were lost: Redis pub/sub is at-most-once. Attempts counts failed re-subscriptions.

type KeyedSubscription

type KeyedSubscription[K, V any] struct {
	// contains filtered or unexported fields
}

KeyedSubscription is one typed stream over several keys of the same topic. It shares Subscription's ownership, sequential receive and failure semantics.

func (*KeyedSubscription[K, V]) Close

func (s *KeyedSubscription[K, V]) Close(ctx context.Context) error

func (*KeyedSubscription[K, V]) Done

func (s *KeyedSubscription[K, V]) Done() <-chan struct{}

func (*KeyedSubscription[K, V]) Err

func (s *KeyedSubscription[K, V]) Err() error

func (*KeyedSubscription[K, V]) Receive

func (s *KeyedSubscription[K, V]) Receive(ctx context.Context) (Delivery[K, V], error)

Receive returns the next payload together with the key it was published to.

type Limits

type Limits struct{ Messages, Bytes, PayloadBytes, Channels int }

Limits bound a subscription's payloads and pending messages. Queue bytes count payload bytes; fixed-size message metadata is additionally bounded by Messages.

func DefaultLimits

func DefaultLimits() Limits

func (Limits) Validate

func (l Limits) Validate() error

type Message

type Message struct {
	Channel Channel
	Data    []byte
}

Message owns its payload. Adapter streams may multiplex exact channels; the typed application API retains its concrete topic and resource key boundary.

type Name

type Name string

type NamedBroker

type NamedBroker struct {
	Name  ConnectionName
	Value *Broker
}

NamedBroker borrows one existing instance. Selection never creates another owner.

type Stats

type Stats struct {
	Operations, Subscriptions int
	Closing                   bool
}

Stats includes setup, live and draining subscriptions until their resources and active callbacks have finished. Reading it performs no I/O.

type Stream

type Stream interface {
	Next(context.Context) (Message, error)
	Close(context.Context) error
	Done() <-chan struct{}
	Err() error
}

Stream is ready when Subscribe returns. Next cancellation stops that wait; Close owns the subscription lifetime and must unblock pending reads. Done closes only after adapter work exits. Errors never imply an uninterrupted subscription. Implementations must not silently drop messages or hide reconnection gaps.

type Subscription

type Subscription[V any] struct {
	// contains filtered or unexported fields
}

Subscription owns one typed stream. Receive is sequential, including JSON decoding; concurrent receives fail instead of creating unbounded waiting work. Terminal stream/decoding failures discard pending delivery and close the stream.

func (*Subscription[V]) Close

func (s *Subscription[V]) Close(ctx context.Context) error

func (*Subscription[V]) Done

func (s *Subscription[V]) Done() <-chan struct{}

func (*Subscription[V]) Err

func (s *Subscription[V]) Err() error

func (*Subscription[V]) Receive

func (s *Subscription[V]) Receive(ctx context.Context) (V, error)

type SupervisePolicy

type SupervisePolicy struct {
	InitialBackoff, MaxBackoff time.Duration
}

SupervisePolicy bounds automatic re-subscription after an interruption. The delay starts at InitialBackoff, doubles (with jitter) after each failed attempt up to MaxBackoff, and resets once delivery has resumed.

func DefaultSupervisePolicy

func DefaultSupervisePolicy() SupervisePolicy

func (SupervisePolicy) Validate

func (p SupervisePolicy) Validate() error

type Topic

type Topic[K, V any] struct {
	// contains filtered or unexported fields
}

Topic retains concrete keys and payloads through publication and subscription.

func (Topic[K, V]) Name

func (t Topic[K, V]) Name() Name

func (Topic[K, V]) Publish

func (t Topic[K, V]) Publish(ctx context.Context, key K, input V) (uint64, error)

Publish snapshots typed JSON using Foundry's shared value validation. The return count describes subscriptions at the authority, not completed application work. A lost acknowledgement is an error even if publication already happened.

func (Topic[K, V]) Subscribe

func (t Topic[K, V]) Subscribe(ctx context.Context, key K) (*Subscription[V], error)

Subscribe waits for confirmed readiness. Its context bounds establishment only; the Broker owns the subscription afterwards. Close it when no longer needed. Receive waits use their own contexts and do not implicitly resubscribe.

func (Topic[K, V]) SubscribeKeys

func (t Topic[K, V]) SubscribeKeys(ctx context.Context, first K, rest ...K) (*KeyedSubscription[K, V], error)

SubscribeKeys confirms readiness for every key in one subscription, whose Receive reports which typed key each payload was published under. Duplicate keys are rejected; the count is bounded by Config.Buffer.Channels. Keys are retained for delivery and must stay immutable while the subscription lives.

func (Topic[K, V]) Supervise

func (t Topic[K, V]) Supervise(ctx context.Context, key K, policy SupervisePolicy, receive func(context.Context, V) error, gap func(context.Context, Gap) error) error

Supervise keeps one key subscribed until ctx ends, the broker closes, or a callback returns an error. receive handles each payload in order. After any terminal interruption (disconnect, overflow, undecodable payload) Supervise re-subscribes with backoff and, once the NEW subscription is confirmed ready, calls gap before delivering anything else, so the application can reconcile state from its source of truth without missing a later change. Changes made while gap runs are queued (within Buffer limits) and delivered afterwards, so receive must tolerate a payload that the reconciliation already reflected. Invalid keys, cycles and contained callback panics end supervision instead of retrying; every ErrDisconnected (including one during establishment) is retried. It returns ctx.Err() on cancellation and ErrClosed on shutdown, the only permanent adapter failure.

func (Topic[K, V]) Validate

func (t Topic[K, V]) Validate() error

func (Topic[K, V]) Version

func (t Topic[K, V]) Version() Version

type Version

type Version uint32

Directories

Path Synopsis
Package memory provides explicit local ephemeral fan-out for pub/sub contracts.
Package memory provides explicit local ephemeral fan-out for pub/sub contracts.

Jump to

Keyboard shortcuts

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