A small, typed, in-memory topic for one-to-many communication in Go.
Topic[T]is identified by the topic value itself; there are no string or generic keys.- Subscriptions use unbuffered, receive-only channels by default;
WithBufferenables bounded buffering for an individual subscription. Publishblocks until every matching active subscriber receives the value.- A publish context can stop waiting and returns its cancellation error.
- Subscription lifetime is controlled by its context; canceling it closes the channel.
SubscribeAs[S]filters heterogeneous topics using Go's normal assignability rules; a nonmatching subscription does not apply backpressure.- The package does not silently buffer, drop, retry, replay, or process messages in internal goroutines.
If a caller wants asynchronous behavior, it explicitly starts a goroutine or adds an application-owned worker or queue.
package main
import (
"context"
"fmt"
"github.com/webermarci/pubsub"
)
type OrderCreated struct {
ID string
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
orders := pubsub.New[OrderCreated]()
events := orders.Subscribe(ctx)
go func() {
for event := range events {
fmt.Printf("new order: %s\n", event.ID)
}
}()
if err := orders.Publish(ctx, OrderCreated{ID: "ORD-12345"}); err != nil {
panic(err)
}
}Every subscriber receives every publication. By default, a slow subscriber applies backpressure to the publisher and to the other subscribers of that topic. An explicit buffer can absorb a bounded burst, but backpressure resumes when it fills. Use a goroutine and an application-owned queue when that is not desired.
Use SubscribeAs[S] when a topic carries an interface and a subscriber only
needs values assignable to a particular concrete or interface type:
type Event interface {
Event()
}
type Started struct{}
func (Started) Event() {}
type Failure interface {
Event
Error() string
}
events := pubsub.New[Event]()
all := events.Subscribe(ctx)
started := events.SubscribeAs[Started](ctx)
failures := events.SubscribeAs[Failure](ctx)all receives every published event. started receives Started values, and
failures receives every value implementing Failure. Matching uses ordinary
Go type assertion and assignability semantics. A nonmatching subscription is
skipped immediately and does not participate in backpressure for that
publication.