events

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Jul 22, 2026 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package events provides an in-process publish/subscribe bus that lets background tasks notify subscribers about state changes without coupling to them. Events are ephemeral: consumers that miss an event are expected to re-read canonical state from disk sidecars. There is no durable storage and no cross-process IPC (see R3 design decision D4).

The cross-plan contract that R2's sse-broker and R5's collection endpoint bind to is the EventBus interface (spec D4.1) — never this concrete channel implementation. Bus is the channel engine behind InProcBus, the builtin backend (spec D4.3); external backends are post-v1 config-selected adapters behind the same interface (spec D4.4). Conformance of any backend is proven mechanically by the eventbustest suite (spec D4.6).

Index

Constants

View Source
const (
	// TopicIterationScored is published after an iteration log entry has
	// been scored and its sidecar written.
	TopicIterationScored = "iteration.scored"
	// TopicRescoreDone is published after a rubric-version rescore pass
	// completes.
	TopicRescoreDone = "rescore.done"
	// TopicTaskError is published when a scheduled task records a failure.
	TopicTaskError = "task.error"
)

Topic identifiers published by R3's background tasks. Consumers match on these constant strings.

View Source
const BuiltinBackendRef = "dotagents-builtin:eventbus/inproc@^1.0"

BuiltinBackendRef is the adapter reference of the in-process builtin backend (spec D4.3). It is the default when no external event_bus adapter is configured; external adapters (D4.4) are post-v1 and demand-gated.

Variables

View Source
var ErrClosed = errors.New("events: bus closed")

ErrClosed is returned by Publish and Subscribe after an EventBus has been closed. Backends must return an error satisfying errors.Is(err, ErrClosed) for post-Close operations so callers can detect shutdown uniformly.

Functions

This section is empty.

Types

type Bus

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

Bus is a concurrency-safe in-process pub/sub bus. The zero value is not usable; construct with NewBus.

func NewBus

func NewBus() *Bus

NewBus returns a ready-to-use Bus.

func (*Bus) Close

func (b *Bus) Close()

Close detaches and closes every subscriber channel and marks the bus closed. Subsequent Publish calls are no-ops and subsequent Subscribe calls return an already-closed channel. Close is idempotent.

func (*Bus) Dropped

func (b *Bus) Dropped() int64

Dropped reports the total number of events discarded across all current subscribers due to drop-oldest back-pressure. Useful for observability.

func (*Bus) Publish

func (b *Bus) Publish(topic string, payload any)

Publish delivers an event on the given topic to every current subscriber.

Delivery is non-blocking: if a subscriber's buffer is full (a slow consumer), the oldest buffered event for that subscriber is discarded to make room for the new one, and the subscriber's dropped counter is incremented. This guarantees Publish never blocks on a slow consumer.

Publishing on a topic with no subscribers, or after Close, is a no-op.

func (*Bus) Subscribe

func (b *Bus) Subscribe(topic string) (<-chan Event, func())

Subscribe registers a consumer for topic and returns a receive-only channel of events plus an unsubscribe function. The channel uses defaultBuffer capacity. Use SubscribeBuffered to choose the capacity.

The returned unsubscribe function removes the subscription and closes the channel. It is safe to call more than once; subsequent calls are no-ops.

func (*Bus) SubscribeBuffered

func (b *Bus) SubscribeBuffered(topic string, buffer int) (<-chan Event, func())

SubscribeBuffered is Subscribe with an explicit per-subscriber buffer capacity. A capacity below 1 is clamped to 1.

type Event

type Event struct {
	Topic     string
	Timestamp time.Time
	Payload   any
}

Event is a single message delivered to subscribers of a topic. Payload is topic-specific and opaque to the bus; subscribers type-assert it.

type EventBus added in v0.5.0

type EventBus interface {
	// Publish delivers payload to all current subscribers of topic.
	// Non-blocking for the publisher (G3); MAY drop events for a slow
	// subscriber per the bounded-buffer / drop-oldest policy. Publishing
	// on a topic with no subscribers succeeds. Returns an error
	// satisfying errors.Is(err, ErrClosed) after Close.
	Publish(topic string, payload any) error
	// Subscribe returns a receive-only stream for topic plus an
	// unsubscribe func. The buffer is bounded; drop-oldest on overflow.
	// The unsubscribe func closes the stream and is safe to call more
	// than once. Returns an error satisfying errors.Is(err, ErrClosed)
	// after Close.
	Subscribe(topic string) (<-chan Event, func(), error)
	// Close drains and releases backend resources, closing every
	// subscriber stream. Close is idempotent.
	Close() error
}

EventBus is the transport seam for service events (spec D4.1). Publishers and subscribers — the scheduler tasks, the transport layer, R2's SSE fan-out, R5's collection endpoint — bind to this interface, never to the concrete channel implementation, so an external backend (Kafka, NATS, Redis) can later be swapped in as a config-selected adapter without a rewrite of any publisher or subscriber.

The interface promises ONLY the D4.2 floor; callers MUST NOT assume any stronger guarantee a particular backend happens to provide:

  • G1 — at-most-once, best-effort delivery. Events are "wake up and look at the new state on disk"; a missed event is recovered by re-reading the canonical sidecar, never from the bus.
  • G2 — per-topic ordering is best-effort, not guaranteed. Code that needs strict order re-derives it from sidecar state.
  • G3 — backpressure is a bounded buffer with drop-oldest; publishers never block on a slow subscriber.
  • G4 — no cross-publish atomicity; every Publish is an independent fire-and-forget.

Backends are free to be stronger; the floor is what app code may assume. Conformance is proven mechanically by the eventbustest suite (spec D4.6).

type InProcBus added in v0.5.0

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

InProcBus adapts the channel-based Bus into the builtin EventBus backend (spec D4.3, dotagents-builtin:eventbus/inproc). It is the default — and in v1 the only — backend: bounded buffer per subscriber, drop-oldest on slow consumers, no durable storage, no cross-process IPC.

The adapter adds the error-reporting shape the D4.1 seam requires on top of the concrete Bus: after Close, Publish and Subscribe return ErrClosed instead of silently no-opping.

func NewInProcBus added in v0.5.0

func NewInProcBus() *InProcBus

NewInProcBus returns a ready-to-use in-process builtin backend.

func (*InProcBus) Close added in v0.5.0

func (p *InProcBus) Close() error

Close implements EventBus: closes every subscriber stream and marks the backend closed. Idempotent; always returns nil.

func (*InProcBus) Dropped added in v0.5.0

func (p *InProcBus) Dropped() int64

Dropped reports the total number of events discarded across current subscribers due to drop-oldest back-pressure (observability passthrough to Bus.Dropped; not part of the EventBus contract).

func (*InProcBus) Publish added in v0.5.0

func (p *InProcBus) Publish(topic string, payload any) error

Publish implements EventBus. Delivery semantics are those of Bus.Publish: non-blocking, drop-oldest per slow subscriber, no-subscriber publishes succeed. Returns ErrClosed after Close.

func (*InProcBus) Subscribe added in v0.5.0

func (p *InProcBus) Subscribe(topic string) (<-chan Event, func(), error)

Subscribe implements EventBus. The stream uses the package default buffer capacity; the unsubscribe func closes the stream and is idempotent. Returns ErrClosed after Close.

type IterationScored added in v0.5.0

type IterationScored struct {
	Iteration   int     `json:"iter"`
	Score       float64 `json:"score"`
	Band        string  `json:"band"`
	SidecarPath string  `json:"sidecar_path"`
}

IterationScored is the payload published on TopicIterationScored after an iteration log entry has been scored and its score sidecar written. Subscribers treat it as a wake-up: the sidecar at SidecarPath is the canonical state (guarantee G1 — a dropped event is recovered by re-reading disk, never from the bus).

type RescoreDone added in v0.5.0

type RescoreDone struct {
	FromVersion string `json:"from_version"`
	ToVersion   string `json:"to_version"`
	IterCount   int    `json:"iter_count"`
}

RescoreDone is the payload published on TopicRescoreDone after a rubric version bump has driven a full-log rescore and the refreshed per-iteration and per-session sidecars are on disk. Subscribers treat it as a wake-up: the sidecars (and the rescore watermark, persisted before this publish) are the canonical state per guarantee G1.

Directories

Path Synopsis
Package eventbustest ships the backend-conformance suite for the events.EventBus transport seam (spec D4.6).
Package eventbustest ships the backend-conformance suite for the events.EventBus transport seam (spec D4.6).

Jump to

Keyboard shortcuts

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