Documentation
¶
Overview ¶
Package routing implements the server-side fanout: it receives proto events from agents (via the AgentService handler) and republishes them to UI subscribers (via the ControlService.StreamEvents handler).
The fanout is intentionally simpler than pkg/observability.Bus:
- Producers send copies, not pooled refcounted events. Once an event reaches the server, it's already off the agent's hot path; the allocation cost is negligible compared to the network IO.
- Drop policy: per-subscription channel, drop-newest on overflow. Counted in EventBus.Stats.
- Filter and per-kind sampling rate are evaluated at fanout time (each subscription has its own filter). This keeps the AGENT-side subscription a single union of all UI demands; the server narrows per UI.
Index ¶
- Variables
- func Wait(ch <-chan *adminv1.SnapshotResponse, cancel func(), timeout time.Duration) (*adminv1.SnapshotResponse, error)
- func WaitDataStudio(ch <-chan *adminv1.DataStudioResponse, cancel func(), timeout time.Duration) (*adminv1.DataStudioResponse, error)
- func WaitRbac(ch <-chan *adminv1.RbacResponse, cancel func(), timeout time.Duration) (*adminv1.RbacResponse, error)
- type AuditEntry
- type AuditRing
- type DataStudioRouter
- type EventBus
- func (b *EventBus) AggregateFilter() *adminv1.Filter
- func (b *EventBus) AggregateSampling() map[string]float32
- func (b *EventBus) HasDemand(t adminv1.EventType) bool
- func (b *EventBus) Publish(e *adminv1.Event) int
- func (b *EventBus) Stats() Stats
- func (b *EventBus) Subscribe(filter *adminv1.Filter, samplingRate map[string]float32, channelSize int) (*EventSubscription, func())
- func (b *EventBus) SubscriberCount() int
- type EventSubscription
- type RbacRouter
- type Replay
- type ReplayCapacities
- type SnapshotRouter
- type Stats
Constants ¶
This section is empty.
Variables ¶
var ErrDataStudioInflightOverflow = errors.New("admin server: too many in-flight data studio requests")
ErrDataStudioInflightOverflow is returned when too many simultaneous data studio requests are pending.
var ErrDataStudioTimeout = errors.New("admin server: data studio request timed out")
ErrDataStudioTimeout is returned when an agent does not answer a DataStudioRequest within the configured timeout.
var ErrRbacInflightOverflow = errors.New("admin server: too many in-flight rbac requests")
ErrRbacInflightOverflow is returned when too many simultaneous rbac requests are pending.
var ErrRbacTimeout = errors.New("admin server: rbac request timed out")
ErrRbacTimeout is returned when an agent does not answer an RbacRequest within the configured timeout.
var ErrSnapshotInflightOverflow = errors.New("admin server: too many in-flight snapshot requests")
ErrSnapshotInflightOverflow is returned when too many simultaneous snapshot requests are pending. This guards against a misbehaving UI flooding the request channel.
var ErrSnapshotTimeout = errors.New("admin server: snapshot request timed out")
ErrSnapshotTimeout is returned when an agent does not answer a SnapshotRequest within the configured timeout.
Functions ¶
func Wait ¶
func Wait(ch <-chan *adminv1.SnapshotResponse, cancel func(), timeout time.Duration) (*adminv1.SnapshotResponse, error)
Wait blocks for a response on ch up to the deadline. Cancel is the cleanup func from Begin (always run, even on success).
func WaitDataStudio ¶
func WaitDataStudio(ch <-chan *adminv1.DataStudioResponse, cancel func(), timeout time.Duration) (*adminv1.DataStudioResponse, error)
WaitDataStudio blocks for a response on ch up to the deadline. Cancel is the cleanup func from Begin (always run, even on success).
func WaitRbac ¶
func WaitRbac(ch <-chan *adminv1.RbacResponse, cancel func(), timeout time.Duration) (*adminv1.RbacResponse, error)
WaitRbac blocks for a response on ch up to the deadline. Cancel is the cleanup func from Begin (always run, even on success).
Types ¶
type AuditEntry ¶
type AuditEntry struct {
Time time.Time
Actor string
Action string // e.g. "datastudio.create"
Target string // human-readable, e.g. `Article #42 ("default")`
NodeID string
}
AuditEntry is one fleet-plane action: something an operator did THROUGH the admin server (Data Studio mutations, and future manage actions). Per-app admin actions stay in each node's in-process Orbit audit ring; this ring covers the fleet plane the server itself routes.
type AuditRing ¶
type AuditRing struct {
// contains filtered or unexported fields
}
AuditRing is a bounded, in-memory, newest-wins ring of fleet-plane audit entries. Same discipline as event replay: never persisted, drop-oldest on overflow.
func NewAuditRing ¶
NewAuditRing constructs a ring. capacity <= 0 defaults to 2048.
func (*AuditRing) Append ¶
func (r *AuditRing) Append(e AuditEntry)
Append records one entry, evicting the oldest when full.
func (*AuditRing) List ¶
func (r *AuditRing) List(limit int) []AuditEntry
List returns up to limit entries, newest first. limit <= 0 means all.
type DataStudioRouter ¶
type DataStudioRouter struct {
// contains filtered or unexported fields
}
DataStudioRouter correlates server-issued DataStudioRequest frames with the DataStudioResponse frames the agent sends back over the same bidi stream. Mirrors the SnapshotRouter pattern.
func NewDataStudioRouter ¶
func NewDataStudioRouter(maxAlive int) *DataStudioRouter
NewDataStudioRouter constructs a router. maxAlive caps the total number of pending requests across all agents; values <= 0 default to 256.
func (*DataStudioRouter) Begin ¶
func (r *DataStudioRouter) Begin() (id string, ch chan *adminv1.DataStudioResponse, cancel func(), err error)
Begin allocates a fresh request_id and registers a channel. The returned cancel MUST be called even on success to release the slot.
func (*DataStudioRouter) PendingCount ¶
func (r *DataStudioRouter) PendingCount() int
PendingCount is intended for tests / metrics.
func (*DataStudioRouter) Resolve ¶
func (r *DataStudioRouter) Resolve(resp *adminv1.DataStudioResponse) bool
Resolve delivers a DataStudioResponse to the awaiting Begin caller (if any). Returns true when a pending request consumed the response.
type EventBus ¶
type EventBus struct {
// contains filtered or unexported fields
}
EventBus is the server-side fanout from agents to UIs.
func (*EventBus) AggregateFilter ¶
AggregateFilter computes the union of every live subscription's Filter (Types and SqlModels are unioned). The server pushes this to each agent as a single Subscribe with id = "server-aggregate", so the agent only has to maintain one bus subscription regardless of how many UIs are open.
HTTP/SQL-specific filters and NodeIDs are NOT aggregated server-side; the per-UI filter is enforced inside Publish via subscription.matches. The agent only needs to know "what kinds to ship and from which models", not how to route to specific UIs.
func (*EventBus) AggregateSampling ¶
AggregateSampling computes the per-kind sampling rate the agent-side aggregate Subscribe should apply: the MAX rate any live subscription wants for that kind (a subscription without an entry wants 1.0 — the proto default). Kinds whose aggregate is 1.0 are omitted. Returns nil when there are no subscribers or nothing samples below 1.0.
Publish compensates for this shared agent-side rate per subscription (see sampleResidual), so a 0.1-rate panel and a 1.0-rate panel can coexist: the agent ships at 1.0 and the server thins the 0.1 panel.
func (*EventBus) HasDemand ¶
HasDemand reports whether at least one subscription matches the given event kind. The agent-service writer uses this to decide whether to shut off ingress when no UI is watching.
func (*EventBus) Publish ¶
Publish fans an event out to every matching subscription. Returns the number of subscribers the event was delivered to (excluding drops).
func (*EventBus) Subscribe ¶
func (b *EventBus) Subscribe(filter *adminv1.Filter, samplingRate map[string]float32, channelSize int) (*EventSubscription, func())
Subscribe registers a new subscription. The caller drains sub.Ch and MUST call cancel exactly once to release resources.
channelSize is the per-subscription buffer. Pass 0 for default 256.
func (*EventBus) SubscriberCount ¶
SubscriberCount returns the total number of live subscriptions.
type EventSubscription ¶
type EventSubscription struct {
// contains filtered or unexported fields
}
EventSubscription is one UI-side subscription. The server creates one per ControlService.StreamEvents call.
func (*EventSubscription) Cancel ¶
func (s *EventSubscription) Cancel()
Cancel removes the subscription from the bus. Idempotent. Does NOT close the channel (per pkg/observability convention) — pending events are GC'd once the consumer stops reading.
func (*EventSubscription) Ch ¶
func (s *EventSubscription) Ch() <-chan *adminv1.Event
Ch returns the subscription's event channel. Each event is owned by the consumer (no Release semantics; it's a proto value).
type RbacRouter ¶
type RbacRouter struct {
// contains filtered or unexported fields
}
RbacRouter correlates server-issued RbacRequest frames with the RbacResponse frames the agent sends back over the same bidi stream. Mirrors the DataStudioRouter/SnapshotRouter pattern.
func NewRbacRouter ¶
func NewRbacRouter(maxAlive int) *RbacRouter
NewRbacRouter constructs a router. maxAlive caps the total number of pending requests across all agents; values <= 0 default to 64.
func (*RbacRouter) Begin ¶
func (r *RbacRouter) Begin() (id string, ch chan *adminv1.RbacResponse, cancel func(), err error)
Begin allocates a fresh request_id and registers a channel. The returned cancel MUST be called even on success to release the slot.
func (*RbacRouter) PendingCount ¶
func (r *RbacRouter) PendingCount() int
PendingCount is intended for tests / metrics.
func (*RbacRouter) Resolve ¶
func (r *RbacRouter) Resolve(resp *adminv1.RbacResponse) bool
Resolve delivers an RbacResponse to the awaiting Begin caller (if any). Returns true when a pending request consumed the response.
type Replay ¶
type Replay struct {
// contains filtered or unexported fields
}
Replay is the per-kind drop-oldest ring buffer the server keeps so a freshly opened UI panel sees a few seconds of recent activity instead of an empty stream.
The buffer holds proto Event copies — they are already off the agent's hot path by the time they reach here, so reuse / pooling is not worth the complexity.
func NewReplay ¶
func NewReplay(c ReplayCapacities) *Replay
NewReplay constructs a Replay with the given capacities.
func (*Replay) LenSnapshot ¶
LenSnapshot returns the per-kind sizes; useful for /metrics gauges.
type ReplayCapacities ¶
ReplayCapacities tunes per-kind capacity. Pass zero on a kind to disable replay for that kind.
type SnapshotRouter ¶
type SnapshotRouter struct {
// contains filtered or unexported fields
}
SnapshotRouter correlates server-issued SnapshotRequest frames with the SnapshotResponse frames the agent sends back over the same bidi stream. Identifiers are short opaque strings allocated at request time.
func NewSnapshotRouter ¶
func NewSnapshotRouter(maxAlive int) *SnapshotRouter
NewSnapshotRouter constructs a router. maxAlive caps the total number of pending requests across all agents; values <= 0 default to 256.
func (*SnapshotRouter) Begin ¶
func (r *SnapshotRouter) Begin() (id string, ch chan *adminv1.SnapshotResponse, cancel func(), err error)
Begin allocates a fresh request_id and registers a channel the caller will block on. The returned cancel MUST be called even on success (after consuming the response) to release the slot.
func (*SnapshotRouter) PendingCount ¶
func (r *SnapshotRouter) PendingCount() int
PendingCount is intended for tests / metrics.
func (*SnapshotRouter) Resolve ¶
func (r *SnapshotRouter) Resolve(resp *adminv1.SnapshotResponse) bool
Resolve delivers a SnapshotResponse to the awaiting Begin caller (if any). Returns true when a pending request consumed the response.