Documentation
¶
Overview ¶
Example ¶
Synchronous handlers run in the goroutine that calls Publish, so the event is fully handled by the time Publish returns.
package main
import (
"fmt"
"github.com/townbell/bus"
)
type UserEvent struct {
UserID string
Action string
}
func main() {
b := bus.NewTyped[UserEvent]()
defer b.Close()
handle := b.SubscribeWithHandle("user.login", func(event UserEvent) {
fmt.Printf("%s performed %s\n", event.UserID, event.Action)
})
defer handle.Unsubscribe()
b.Publish("user.login", UserEvent{UserID: "u-1", Action: "login"})
}
Output: u-1 performed login
Index ¶
- type Bus
- type BusController
- type BusPublisher
- type BusSubscriber
- type ControlledSubscriber
- type DefaultLogger
- func (l *DefaultLogger) Debug(msg string, args ...interface{})
- func (l *DefaultLogger) Error(msg string, args ...interface{})
- func (l *DefaultLogger) GetLevel() LogLevel
- func (l *DefaultLogger) Info(msg string, args ...interface{})
- func (l *DefaultLogger) SetLevel(level LogLevel)
- func (l *DefaultLogger) Warn(msg string, args ...interface{})
- type DefaultMetrics
- func (m *DefaultMetrics) DecrementSubscribers()
- func (m *DefaultMetrics) GetHandlerStats() map[string]HandlerMetricsSnapshot
- func (m *DefaultMetrics) GetStats() (published, processed, failed int64, activeSubscribers int32)
- func (m *DefaultMetrics) GetTopicStats() map[string]TopicMetricsSnapshot
- func (m *DefaultMetrics) IncrementFailed()
- func (m *DefaultMetrics) IncrementProcessed()
- func (m *DefaultMetrics) IncrementPublished()
- func (m *DefaultMetrics) IncrementSubscribers()
- func (m *DefaultMetrics) RecordFailed(topic, handlerID string, duration time.Duration)
- func (m *DefaultMetrics) RecordProcessed(topic, handlerID string, duration time.Duration)
- func (m *DefaultMetrics) RecordPublished(topic string)
- type DetailedMetrics
- type ErrorHandler
- type EventBus
- func (bus *EventBus[T]) AddMiddleware(middleware EventMiddleware[any])
- func (bus *EventBus[T]) Close() error
- func (bus *EventBus[T]) GetLogger() Logger
- func (bus *EventBus[T]) GetMetrics() Metrics
- func (bus *EventBus[T]) GetSubscriberCount(topic string) int
- func (bus *EventBus[T]) GetTopics() []string
- func (bus *EventBus[T]) HasCallback(topic string) bool
- func (bus *EventBus[T]) Publish(topic string, event T)
- func (bus *EventBus[T]) PublishWithContext(ctx context.Context, topic string, event T) error
- func (bus *EventBus[T]) PublishWithTimeout(topic string, event T, timeout time.Duration) error
- func (bus *EventBus[T]) SetErrorHandler(handler ErrorHandler)
- func (bus *EventBus[T]) SetLogger(logger Logger)
- func (bus *EventBus[T]) Subscribe(topic string, fn func(T)) error
- func (bus *EventBus[T]) SubscribeAsync(topic string, fn func(T), transactional bool) error
- func (bus *EventBus[T]) SubscribeAsyncWithHandle(topic string, fn func(T), transactional bool) *Handle[T]
- func (bus *EventBus[T]) SubscribeOnce(topic string, fn func(T)) error
- func (bus *EventBus[T]) SubscribeOnceAsync(topic string, fn func(T)) error
- func (bus *EventBus[T]) SubscribeWithContext(ctx context.Context, topic string, fn func(T)) *Handle[T]
- func (bus *EventBus[T]) SubscribeWithFilter(topic string, fn func(T), filter EventFilter[T]) *Handle[T]
- func (bus *EventBus[T]) SubscribeWithHandle(topic string, fn func(T)) *Handle[T]
- func (bus *EventBus[T]) SubscribeWithOptions(topic string, fn func(T), options ...HandlerOption) (*Handle[T], error)
- func (bus *EventBus[T]) SubscribeWithPriority(topic string, fn func(T), priority Priority) *Handle[T]
- func (bus *EventBus[T]) WaitAsync()
- type EventError
- type EventFilter
- type EventMiddleware
- type Handle
- type HandlerMetricsSnapshot
- type HandlerOption
- func HandlerAsync(transactional bool) HandlerOption
- func HandlerContext(ctx context.Context) HandlerOption
- func HandlerMaxConcurrency(limit int) HandlerOption
- func HandlerOnce() HandlerOption
- func HandlerPriority(priority Priority) HandlerOption
- func HandlerRecoverPolicy(policy RecoverPolicy) HandlerOption
- func HandlerSerial() HandlerOption
- func HandlerTimeout(timeout time.Duration) HandlerOption
- type LogLevel
- type Logger
- type Metrics
- type NoOpLogger
- func (l *NoOpLogger) Debug(msg string, args ...interface{})
- func (l *NoOpLogger) Error(msg string, args ...interface{})
- func (l *NoOpLogger) GetLevel() LogLevel
- func (l *NoOpLogger) Info(msg string, args ...interface{})
- func (l *NoOpLogger) SetLevel(level LogLevel)
- func (l *NoOpLogger) Warn(msg string, args ...interface{})
- type Option
- type Priority
- type RecoverPolicy
- type TopicMetricsSnapshot
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Bus ¶
type Bus[T any] interface { BusController BusSubscriber[T] BusPublisher[T] }
Bus englobes global (subscribe, publish, control) bus behavior
type BusController ¶
type BusController interface {
HasCallback(topic string) bool
WaitAsync()
GetMetrics() Metrics
SetErrorHandler(handler ErrorHandler)
AddMiddleware(middleware EventMiddleware[any])
SetLogger(logger Logger)
GetLogger() Logger
GetTopics() []string
GetSubscriberCount(topic string) int
Close() error
}
BusController defines bus control behavior
type BusPublisher ¶
type BusPublisher[T any] interface { Publish(topic string, event T) PublishWithContext(ctx context.Context, topic string, event T) error PublishWithTimeout(topic string, event T, timeout time.Duration) error }
BusPublisher defines publishing-related bus behavior
type BusSubscriber ¶
type BusSubscriber[T any] interface { Subscribe(topic string, fn func(T)) error SubscribeAsync(topic string, fn func(T), transactional bool) error SubscribeOnce(topic string, fn func(T)) error SubscribeOnceAsync(topic string, fn func(T)) error SubscribeWithHandle(topic string, fn func(T)) *Handle[T] SubscribeAsyncWithHandle(topic string, fn func(T), transactional bool) *Handle[T] SubscribeWithPriority(topic string, fn func(T), priority Priority) *Handle[T] SubscribeWithFilter(topic string, fn func(T), filter EventFilter[T]) *Handle[T] SubscribeWithContext(ctx context.Context, topic string, fn func(T)) *Handle[T] }
BusSubscriber defines subscription-related bus behavior
type ControlledSubscriber ¶
type ControlledSubscriber[T any] interface { SubscribeWithOptions(topic string, fn func(T), options ...HandlerOption) (*Handle[T], error) }
ControlledSubscriber defines optional handler-level execution control behavior.
type DefaultLogger ¶
type DefaultLogger struct {
// contains filtered or unexported fields
}
DefaultLogger is the default logger implementation using Go's standard log package
func NewDefaultLogger ¶
func NewDefaultLogger() *DefaultLogger
NewDefaultLogger creates a new default logger instance
func NewDefaultLoggerWithOutput ¶
func NewDefaultLoggerWithOutput(output *os.File, prefix string) *DefaultLogger
NewDefaultLoggerWithOutput creates a new default logger with custom output
func (*DefaultLogger) Debug ¶
func (l *DefaultLogger) Debug(msg string, args ...interface{})
Debug logs a debug message
func (*DefaultLogger) Error ¶
func (l *DefaultLogger) Error(msg string, args ...interface{})
Error logs an error message
func (*DefaultLogger) GetLevel ¶
func (l *DefaultLogger) GetLevel() LogLevel
GetLevel returns the current log level
func (*DefaultLogger) Info ¶
func (l *DefaultLogger) Info(msg string, args ...interface{})
Info logs an info message
func (*DefaultLogger) SetLevel ¶
func (l *DefaultLogger) SetLevel(level LogLevel)
SetLevel sets the minimum log level
func (*DefaultLogger) Warn ¶
func (l *DefaultLogger) Warn(msg string, args ...interface{})
Warn logs a warning message
type DefaultMetrics ¶
type DefaultMetrics struct {
PublishedEvents int64
ProcessedEvents int64
FailedEvents int64
ActiveSubscribers int32
// contains filtered or unexported fields
}
DefaultMetrics is the default implementation of the Metrics interface
func (*DefaultMetrics) DecrementSubscribers ¶
func (m *DefaultMetrics) DecrementSubscribers()
func (*DefaultMetrics) GetHandlerStats ¶
func (m *DefaultMetrics) GetHandlerStats() map[string]HandlerMetricsSnapshot
GetHandlerStats returns a snapshot of per-handler metrics.
func (*DefaultMetrics) GetStats ¶
func (m *DefaultMetrics) GetStats() (published, processed, failed int64, activeSubscribers int32)
func (*DefaultMetrics) GetTopicStats ¶
func (m *DefaultMetrics) GetTopicStats() map[string]TopicMetricsSnapshot
GetTopicStats returns a snapshot of per-topic metrics.
func (*DefaultMetrics) IncrementFailed ¶
func (m *DefaultMetrics) IncrementFailed()
func (*DefaultMetrics) IncrementProcessed ¶
func (m *DefaultMetrics) IncrementProcessed()
func (*DefaultMetrics) IncrementPublished ¶
func (m *DefaultMetrics) IncrementPublished()
func (*DefaultMetrics) IncrementSubscribers ¶
func (m *DefaultMetrics) IncrementSubscribers()
func (*DefaultMetrics) RecordFailed ¶
func (m *DefaultMetrics) RecordFailed(topic, handlerID string, duration time.Duration)
RecordFailed records a failed handler execution.
func (*DefaultMetrics) RecordProcessed ¶
func (m *DefaultMetrics) RecordProcessed(topic, handlerID string, duration time.Duration)
RecordProcessed records a successful handler execution.
func (*DefaultMetrics) RecordPublished ¶
func (m *DefaultMetrics) RecordPublished(topic string)
RecordPublished records a published event for a topic.
type DetailedMetrics ¶
type DetailedMetrics interface {
Metrics
RecordPublished(topic string)
RecordProcessed(topic, handlerID string, duration time.Duration)
RecordFailed(topic, handlerID string, duration time.Duration)
}
DetailedMetrics is an optional metrics extension for topic and handler level data.
type ErrorHandler ¶
type ErrorHandler func(err *EventError)
ErrorHandler defines how to handle errors during event processing
type EventBus ¶
type EventBus[T any] struct { // contains filtered or unexported fields }
EventBus - box for handlers and callbacks.
func (*EventBus[T]) AddMiddleware ¶
func (bus *EventBus[T]) AddMiddleware(middleware EventMiddleware[any])
AddMiddleware adds middleware to the bus
Example ¶
Middleware wraps the whole dispatch. Calling next runs the remaining middleware and then the handlers; not calling it intercepts the event.
package main
import (
"fmt"
"github.com/townbell/bus"
)
func main() {
b := bus.NewTyped[string]()
defer b.Close()
b.AddMiddleware(func(topic string, event any, next func()) error {
fmt.Println("before", topic)
next()
fmt.Println("after", topic)
return nil
})
_ = b.Subscribe("job.run", func(id string) {
fmt.Println("handling", id)
})
b.Publish("job.run", "j-1")
}
Output: before job.run handling j-1 after job.run
func (*EventBus[T]) GetMetrics ¶
GetMetrics returns the current metrics
Example ¶
package main
import (
"fmt"
"github.com/townbell/bus"
)
func main() {
b := bus.NewTyped[string]()
defer b.Close()
_ = b.Subscribe("job.run", func(string) {})
b.Publish("job.run", "j-1")
b.Publish("job.run", "j-2")
published, processed, failed, subscribers := b.GetMetrics().GetStats()
fmt.Println(published, processed, failed, subscribers)
}
Output: 2 2 0 1
func (*EventBus[T]) GetSubscriberCount ¶
GetSubscriberCount returns the number of subscribers for a topic
func (*EventBus[T]) HasCallback ¶
HasCallback returns true if exists any callback subscribed to the topic.
func (*EventBus[T]) PublishWithContext ¶
PublishWithContext publishes an event with context
Example ¶
Publish discards errors. Use PublishWithContext when cancellation, timeout or closed-bus errors matter.
package main
import (
"context"
"fmt"
"github.com/townbell/bus"
)
func main() {
b := bus.NewTyped[string]()
b.Close()
err := b.PublishWithContext(context.Background(), "user.created", "u-1")
fmt.Println("err:", err)
}
Output: err: event bus is closed
func (*EventBus[T]) PublishWithTimeout ¶
PublishWithTimeout publishes an event with timeout
func (*EventBus[T]) SetErrorHandler ¶
func (bus *EventBus[T]) SetErrorHandler(handler ErrorHandler)
SetErrorHandler sets the error handler for the bus
func (*EventBus[T]) Subscribe ¶
Subscribe subscribes to a topic.
Example (Wildcard) ¶
The "*" topic receives every event. Wildcard handlers are merged with the topic's own handlers and ordered by priority.
package main
import (
"fmt"
"github.com/townbell/bus"
)
func main() {
b := bus.NewTyped[string]()
defer b.Close()
_ = b.Subscribe("user.created", func(payload string) {
fmt.Println("welcome:", payload)
})
_ = b.Subscribe("*", func(payload string) {
fmt.Println("audit:", payload)
})
b.Publish("user.created", "u-1")
}
Output: welcome: u-1 audit: u-1
func (*EventBus[T]) SubscribeAsync ¶
SubscribeAsync subscribes to a topic with an asynchronous callback
func (*EventBus[T]) SubscribeAsyncWithHandle ¶
func (bus *EventBus[T]) SubscribeAsyncWithHandle(topic string, fn func(T), transactional bool) *Handle[T]
SubscribeAsyncWithHandle subscribes to a topic with an asynchronous callback and returns a handle.
func (*EventBus[T]) SubscribeOnce ¶
SubscribeOnce subscribes to a topic once. Handler will be removed after executing.
func (*EventBus[T]) SubscribeOnceAsync ¶
SubscribeOnceAsync subscribes to a topic once with an asynchronous callback
func (*EventBus[T]) SubscribeWithContext ¶
func (bus *EventBus[T]) SubscribeWithContext(ctx context.Context, topic string, fn func(T)) *Handle[T]
SubscribeWithContext subscribes to a topic with context for cancellation
func (*EventBus[T]) SubscribeWithFilter ¶
func (bus *EventBus[T]) SubscribeWithFilter(topic string, fn func(T), filter EventFilter[T]) *Handle[T]
SubscribeWithFilter subscribes to a topic with an event filter
Example ¶
A filter decides per event whether its handler runs at all.
package main
import (
"fmt"
"strings"
"github.com/townbell/bus"
)
type UserEvent struct {
UserID string
Action string
}
func main() {
b := bus.NewTyped[UserEvent]()
defer b.Close()
b.SubscribeWithFilter("user.action", func(event UserEvent) {
fmt.Println("admin action:", event.Action)
}, func(topic string, event UserEvent) bool {
return strings.HasPrefix(event.UserID, "admin-")
})
b.Publish("user.action", UserEvent{UserID: "u-1", Action: "read"})
b.Publish("user.action", UserEvent{UserID: "admin-1", Action: "delete"})
}
Output: admin action: delete
func (*EventBus[T]) SubscribeWithHandle ¶
SubscribeWithHandle subscribes to a topic and returns a handle for unsubscription.
func (*EventBus[T]) SubscribeWithOptions ¶
func (bus *EventBus[T]) SubscribeWithOptions(topic string, fn func(T), options ...HandlerOption) (*Handle[T], error)
SubscribeWithOptions subscribes to a topic with handler-level execution controls.
Example ¶
SubscribeWithOptions is the extensible subscription path. It is the only helper that reports why a subscription was rejected.
package main
import (
"fmt"
"time"
"github.com/townbell/bus"
)
func main() {
b := bus.NewTyped[string]()
defer b.Close()
handle, err := b.SubscribeWithOptions("payment.validate",
func(id string) { fmt.Println("validating", id) },
bus.HandlerPriority(bus.PriorityHigh),
bus.HandlerTimeout(2*time.Second),
bus.HandlerRecoverPolicy(bus.RecoverAndStop),
bus.HandlerSerial(),
)
if err != nil {
fmt.Println("subscribe failed:", err)
return
}
defer handle.Unsubscribe()
b.Publish("payment.validate", "p-1")
}
Output: validating p-1
func (*EventBus[T]) SubscribeWithPriority ¶
func (bus *EventBus[T]) SubscribeWithPriority(topic string, fn func(T), priority Priority) *Handle[T]
SubscribeWithPriority subscribes to a topic with specified priority
Example ¶
Handlers run from the highest priority to the lowest. Handlers registered at the same priority keep their registration order.
package main
import (
"fmt"
"github.com/townbell/bus"
)
func main() {
b := bus.NewTyped[string]()
defer b.Close()
b.SubscribeWithPriority("order.placed", func(string) {
fmt.Println("3. analytics")
}, bus.PriorityLow)
b.SubscribeWithPriority("order.placed", func(string) {
fmt.Println("1. fraud check")
}, bus.PriorityCritical)
b.SubscribeWithPriority("order.placed", func(string) {
fmt.Println("2. fulfilment")
}, bus.PriorityNormal)
b.Publish("order.placed", "o-1")
}
Output: 1. fraud check 2. fulfilment 3. analytics
type EventError ¶
EventError represents an error that occurred during event handling
func (*EventError) Error ¶
func (e *EventError) Error() string
type EventFilter ¶
EventFilter allows filtering events before they reach handlers
type EventMiddleware ¶
EventMiddleware allows intercepting events before and after processing
type Handle ¶
type Handle[T any] struct { // contains filtered or unexported fields }
Handle represents a subscription handle that can be used to unsubscribe
func (*Handle[T]) IsActive ¶
IsActive returns whether this handle is still active. A nil handle is never active.
func (*Handle[T]) Unsubscribe ¶
Unsubscribe removes this specific subscription.
A nil handle is reported as an error rather than a panic. Subscribe helpers that return only a handle yield nil when the subscription is rejected (nil callback, or a closed bus), so a deferred Unsubscribe must stay safe.
Example (NilHandle) ¶
Subscribe helpers that return only a handle yield nil when the subscription is rejected. The returned handle stays safe to use, so a deferred Unsubscribe never panics.
package main
import (
"fmt"
"github.com/townbell/bus"
)
func main() {
b := bus.NewTyped[string]()
b.Close()
handle := b.SubscribeWithHandle("user.created", func(string) {})
fmt.Println("active:", handle.IsActive())
fmt.Println("err:", handle.Unsubscribe())
}
Output: active: false err: handle is nil: the subscription was never created
type HandlerMetricsSnapshot ¶
type HandlerMetricsSnapshot struct {
Topic string
ProcessedEvents int64
FailedEvents int64
TotalDuration time.Duration
}
HandlerMetricsSnapshot is a read-only copy of metrics for a handler.
type HandlerOption ¶
type HandlerOption func(*handlerOptions)
HandlerOption configures a subscription created with SubscribeWithOptions.
func HandlerAsync ¶
func HandlerAsync(transactional bool) HandlerOption
HandlerAsync runs the handler in a goroutine. Set transactional to true to serialize this handler.
func HandlerContext ¶
func HandlerContext(ctx context.Context) HandlerOption
HandlerContext sets a context that can disable the handler when canceled.
func HandlerMaxConcurrency ¶
func HandlerMaxConcurrency(limit int) HandlerOption
HandlerMaxConcurrency limits concurrent executions of this handler. Values below 1 mean unlimited.
func HandlerOnce ¶
func HandlerOnce() HandlerOption
HandlerOnce removes the handler before its first dispatch attempt.
func HandlerPriority ¶
func HandlerPriority(priority Priority) HandlerOption
HandlerPriority sets the handler priority.
func HandlerRecoverPolicy ¶
func HandlerRecoverPolicy(policy RecoverPolicy) HandlerOption
HandlerRecoverPolicy sets how recovered panics affect the current publish call.
func HandlerSerial ¶
func HandlerSerial() HandlerOption
HandlerSerial limits this handler to one execution at a time.
func HandlerTimeout ¶
func HandlerTimeout(timeout time.Duration) HandlerOption
HandlerTimeout bounds how long PublishWithContext waits for this handler.
type Logger ¶
type Logger interface {
// Debug logs a debug message
Debug(msg string, args ...interface{})
// Info logs an info message
Info(msg string, args ...interface{})
// Warn logs a warning message
Warn(msg string, args ...interface{})
// Error logs an error message
Error(msg string, args ...interface{})
// SetLevel sets the minimum log level
SetLevel(level LogLevel)
// GetLevel returns the current log level
GetLevel() LogLevel
}
Logger defines the interface for logging within the event bus
type Metrics ¶
type Metrics interface {
IncrementPublished()
IncrementProcessed()
IncrementFailed()
IncrementSubscribers()
DecrementSubscribers()
GetStats() (published, processed, failed int64, activeSubscribers int32)
}
Metrics defines the monitoring interface for the event bus
type NoOpLogger ¶
type NoOpLogger struct{}
NoOpLogger is a logger that does nothing (useful for disabling logging)
func (*NoOpLogger) Debug ¶
func (l *NoOpLogger) Debug(msg string, args ...interface{})
Debug does nothing
func (*NoOpLogger) Error ¶
func (l *NoOpLogger) Error(msg string, args ...interface{})
Error does nothing
func (*NoOpLogger) GetLevel ¶
func (l *NoOpLogger) GetLevel() LogLevel
GetLevel returns LogLevelError (highest level to disable all logging)
func (*NoOpLogger) Info ¶
func (l *NoOpLogger) Info(msg string, args ...interface{})
Info does nothing
func (*NoOpLogger) Warn ¶
func (l *NoOpLogger) Warn(msg string, args ...interface{})
Warn does nothing
type Option ¶
Option defines a functional option for EventBus
func WithErrorHandler ¶
func WithErrorHandler[T any](handler ErrorHandler) Option[T]
WithErrorHandler sets a custom error handler for the EventBus
func WithLogger ¶
WithLogger sets a custom logger for the EventBus
func WithMetrics ¶
WithMetrics allows custom Metrics implementation
func WithMiddleware ¶
func WithMiddleware[T any](middleware EventMiddleware[any]) Option[T]
WithMiddleware adds a middleware to the EventBus
type RecoverPolicy ¶
type RecoverPolicy int
RecoverPolicy controls how handler panics are reported to the publisher.
const ( // RecoverAndContinue records panics and continues dispatching later handlers. RecoverAndContinue RecoverPolicy = iota // RecoverAndStop records panics and stops the current publish call. RecoverAndStop )