Documentation
¶
Overview ¶
Package eventbridge provides an event bus system for communication between AI Studio (control) and Microgateway (edge) nodes using simonfxr/pubsub for in-process event buses and gRPC for cross-node event forwarding.
Index ¶
- Constants
- func PublishDown(bus Bus, nodeID, topic string, payload interface{}) error
- func PublishLocal(bus Bus, nodeID, topic string, payload interface{}) error
- func PublishUp(bus Bus, nodeID, topic string, payload interface{}) error
- type Bridge
- type BridgeConfig
- type Bus
- type Direction
- type Event
- type EventFrame
- type EventFrameCreator
- type GRPCStream
- type ProtoEventFrame
- type PubSubBus
- type StreamAdapter
- func (a *StreamAdapter) Close()
- func (a *StreamAdapter) EnqueueEvent(frame *EventFrame) bool
- func (a *StreamAdapter) EnqueueProtoEvent(protoFrame ProtoEventFrame) bool
- func (a *StreamAdapter) IsClosed() bool
- func (a *StreamAdapter) RecvEvent() (*EventFrame, error)
- func (a *StreamAdapter) SendEvent(frame *EventFrame) error
Constants ¶
const (
// BudgetSyncTopic is used for budget synchronization between control and edge nodes
BudgetSyncTopic = "budget.sync"
)
Well-known event topics for cross-node communication
Variables ¶
This section is empty.
Functions ¶
func PublishDown ¶
PublishDown is a helper to publish events from control to edges.
func PublishLocal ¶
PublishLocal is a helper to publish local-only events that won't be forwarded.
Types ¶
type Bridge ¶
type Bridge struct {
// contains filtered or unexported fields
}
Bridge connects a local event bus to a gRPC stream, forwarding events based on their direction while preventing feedback loops.
The bridge runs two goroutines: - localToRemote: subscribes to local bus and forwards events over gRPC - remoteToLocal: reads from gRPC and republishes into local bus
Feedback loops are prevented by: 1. Remote events are always marked as DirLocal when republished 2. Outbound loop only forwards events matching the node's role:
- Control node only forwards DirDown events
- Edge nodes only forward DirUp events
func NewBridge ¶
func NewBridge(config BridgeConfig, bus Bus, stream GRPCStream) *Bridge
NewBridge creates a new bridge instance. The bridge is not started until Start() is called.
type BridgeConfig ¶
type BridgeConfig struct {
// NodeID is the identifier for this node ("control" or "edge-xxx")
NodeID string
// IsControl indicates if this is the control node (true) or an edge (false)
IsControl bool
// Topics is an optional list of topics to export. If empty, all topics are exported.
Topics []string
}
BridgeConfig configures the bridge behavior.
type Bus ¶
type Bus interface {
// Subscribe registers a callback for events on a specific topic.
// Returns a subscription that can be used to unsubscribe.
Subscribe(topic string, fn func(Event)) *pubsub.Subscription
// SubscribeAll registers a callback for all events regardless of topic.
// Returns a subscription that can be used to unsubscribe.
SubscribeAll(fn func(Event)) *pubsub.Subscription
// Unsubscribe removes a subscription.
Unsubscribe(sub *pubsub.Subscription)
// Publish sends an event to all subscribers of the event's topic.
Publish(event Event)
}
Bus is the interface for the local event bus. It provides publish/subscribe functionality for Event objects.
type Direction ¶
type Direction int
Direction controls event routing and prevents feedback loops. Events are routed based on their direction: - DirLocal: Events stay on the local bus, never forwarded - DirUp: Events flow from edge to control - DirDown: Events flow from control to edge(s)
func DirectionFromInt32 ¶
DirectionFromInt32 converts a protobuf int32 to Direction.
type Event ¶
type Event struct {
// ID is a UUID for deduplication and tracing
ID string `json:"id"`
// Topic is the logical topic name (e.g., "config.update", "metrics.report")
Topic string `json:"topic"`
// Origin is the node ID that created the event (e.g., "control" or "edge-123")
Origin string `json:"origin"`
// Dir controls routing: DirLocal stays local, DirUp goes to control, DirDown goes to edges
Dir Direction `json:"dir"`
// Payload is the application-specific data as JSON
Payload json.RawMessage `json:"payload"`
// RelayedFrom is set on a control-plane replica when the event was
// published on another replica and relayed through the cluster event
// log (pkg/cluster.Relay); it names that replica. It is local metadata:
// never serialized, never sent to edges or plugins. Consumers that act
// once for the whole cluster (a checksum recompute, say) skip relayed
// events; consumers that keep per-replica state act on them.
RelayedFrom string `json:"-"`
// FromEdge is set on a control plane for an event one of its edges sent
// over its stream. The bridge republishes those as DirLocal (so they are
// never forwarded again), which leaves this the only way to tell them
// from events published on the control plane itself. A headless control
// plane relays them to the replicas that host plugins. Local metadata,
// like RelayedFrom: never serialized.
FromEdge bool `json:"-"`
}
Event is the canonical event type used on the local bus and for gRPC transport. All application code publishes and subscribes using this Event type.
func NewEventRaw ¶
func NewEventRaw(topic, origin string, dir Direction, payload json.RawMessage) Event
NewEventRaw creates a new event with pre-marshaled JSON payload.
func (*Event) ToEventFrame ¶
func (e *Event) ToEventFrame() *EventFrame
ToEventFrame converts an Event to an EventFrame for wire transmission.
type EventFrame ¶
type EventFrame struct {
ID string
Topic string
Origin string
Dir int32 // 0 = Local, 1 = Up, 2 = Down (matches Direction enum)
Payload []byte
}
EventFrame is the wire format for events over gRPC. This mirrors the protobuf EventFrame message structure.
func (*EventFrame) ToEvent ¶
func (f *EventFrame) ToEvent() Event
ToEvent converts an EventFrame to an Event with DirLocal direction. This is used when receiving events from remote nodes to prevent re-forwarding.
type EventFrameCreator ¶
EventFrameCreator is a function type for creating proto EventFrame objects
type GRPCStream ¶
type GRPCStream interface {
// SendEvent sends an event frame to the remote end
SendEvent(frame *EventFrame) error
// RecvEvent receives an event frame from the remote end (blocking)
RecvEvent() (*EventFrame, error)
}
GRPCStream is the interface for sending/receiving event frames over gRPC. This abstraction allows the bridge to work with different stream implementations.
type ProtoEventFrame ¶
type ProtoEventFrame interface {
GetId() string
GetTopic() string
GetOrigin() string
GetDir() int32
GetPayload() []byte
}
ProtoEventFrame is an interface that matches the generated pb.EventFrame This allows the adapter to work with the proto types without importing them directly
type PubSubBus ¶
type PubSubBus struct {
// contains filtered or unexported fields
}
PubSubBus wraps simonfxr/pubsub as a Bus implementation. It is safe for concurrent use.
func (*PubSubBus) Publish ¶
Publish sends an event to all subscribers of the event's topic and to all wildcard subscribers.
func (*PubSubBus) Subscribe ¶
func (b *PubSubBus) Subscribe(topic string, fn func(Event)) *pubsub.Subscription
Subscribe registers a callback for events on a specific topic.
func (*PubSubBus) SubscribeAll ¶
func (b *PubSubBus) SubscribeAll(fn func(Event)) *pubsub.Subscription
SubscribeAll registers a callback for all events. This is implemented by subscribing to a special wildcard topic that receives all published events.
func (*PubSubBus) Unsubscribe ¶
func (b *PubSubBus) Unsubscribe(sub *pubsub.Subscription)
Unsubscribe removes a subscription.
type StreamAdapter ¶
type StreamAdapter struct {
// SendFunc is called to send an event frame over gRPC
// The frame parameter is an *EventFrame from this package
SendFunc func(frame *EventFrame) error
// contains filtered or unexported fields
}
StreamAdapter wraps a gRPC bidirectional stream to implement GRPCStream. It provides a channel-based interface for receiving events that can be populated from the main message processing loop.
func NewStreamAdapter ¶
func NewStreamAdapter(sendFunc func(frame *EventFrame) error, bufferSize int) *StreamAdapter
NewStreamAdapter creates a new StreamAdapter. bufferSize controls the channel buffer for incoming events.
func (*StreamAdapter) Close ¶
func (a *StreamAdapter) Close()
Close closes the event channel, causing RecvEvent to return an error.
func (*StreamAdapter) EnqueueEvent ¶
func (a *StreamAdapter) EnqueueEvent(frame *EventFrame) bool
EnqueueEvent adds an event to the receive channel from the main message loop. This should be called when an event message is received on the gRPC stream. Returns false if the adapter is closed or the channel is full.
func (*StreamAdapter) EnqueueProtoEvent ¶
func (a *StreamAdapter) EnqueueProtoEvent(protoFrame ProtoEventFrame) bool
EnqueueProtoEvent converts a proto EventFrame to our EventFrame and enqueues it. This is a convenience method for use in message processing loops.
func (*StreamAdapter) IsClosed ¶
func (a *StreamAdapter) IsClosed() bool
IsClosed returns whether the adapter has been closed.
func (*StreamAdapter) RecvEvent ¶
func (a *StreamAdapter) RecvEvent() (*EventFrame, error)
RecvEvent implements GRPCStream.RecvEvent by reading from the event channel. This blocks until an event is available or the adapter is closed.
func (*StreamAdapter) SendEvent ¶
func (a *StreamAdapter) SendEvent(frame *EventFrame) error
SendEvent implements GRPCStream.SendEvent by calling the configured SendFunc.