feed

package
v0.2.7 Latest Latest
Warning

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

Go to latest
Published: Jun 8, 2026 License: MPL-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package feed is the control-event feed seam: where a chassis reads the ordered stream of control events it must apply to stay in sync.

An event is a notification + a content-addressed artifact reference (see chassis/controlevent and internal docs/todo-architecture-saas-fleet.md §3.1); the feed only carries the small events, never the payload. The backend is selected by name through a registry, so an additional backend can be added without changing this package or its callers. The built-in "nop" backend disables the feed (single-node default); "file" reads events from a local directory.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Register

func Register(name string, c Constructor)

Register adds a backend constructor. Called from a backend package's init(); the chassis activates a backend with a blank import.

func RegisterSink

func RegisterSink(name string, c SinkConstructor)

RegisterSink adds a Sink backend. Called from a backend package's init(); the chassis activates a backend with a blank import.

Types

type Acker

type Acker interface {
	Ack(ctx context.Context, eventID string) error
}

Acker is an optional interface a Source implements when its events need explicit acknowledgement after a successful local apply. The applier calls Ack(eventID) only after the SQLite tx that wrote applied_events + the data rows + the cursor advance commits — so a crash between fetch and ack causes the broker to redeliver, and the consumer-side applied_events guard makes the replay a no-op.

Sources that don't need per-event acks (e.g. the built-in file source, which reads from a directory and has no broker-side cursor) simply don't implement this interface. The applier type-asserts and falls back to a no-op when absent.

JetStream pull consumers in the service overlay are the primary implementor today (overlay/nats/controlfeed/source.go): they retain the per-message ack handle keyed by EventID until the applier confirms apply, then `AckSync` against the broker.

type Constructor

type Constructor func(SourceConfig) (Source, error)

Constructor builds a Source from resolved config.

type Sink

type Sink interface {
	// Append publishes one event to the feed. Input has EventID
	// populated (from outbox.event_id) and ControlVersion==0. On
	// success the returned event carries the broker-assigned
	// ControlVersion; on error the input is returned unchanged so the
	// pump's diagnostic logging has the originating event_id.
	Append(ctx context.Context, e controlevent.Event) (controlevent.Event, error)

	// Name is the backend identity (for logs).
	Name() string
}

Sink is the producer-side seam: a chassis writes one event into the fleet feed and gets back the same event stamped with its broker-assigned ControlVersion. Mirror of Source going the other direction — registered the same way (init + blank import), opened by name from --feed-sink.

The pump (chassis/controlpublish) drains the outbox and calls Append once per pending row. Implementations MUST use the event's EventID as their idempotent-publish key (Nats-Msg-Id on JetStream, filename on the file backend); retries with the same EventID must resolve to the same ControlVersion within the backend's dedup window. Beyond the dedup window, the consumer-side applied_events table is the load-bearing guard.

Append is single-call-per-event from the pump's point of view; an error sends the row back to the pending set for retry (with attempt_count + last_error bookkeeping). On success the pump writes published_control_version + published_at back to the outbox.

func OpenSink

func OpenSink(name string, cfg SourceConfig) (Sink, error)

OpenSink constructs the named Sink backend. Unknown name is a startup error listing what is available.

type SinkConstructor

type SinkConstructor func(SourceConfig) (Sink, error)

SinkConstructor builds a Sink from resolved config. Same SourceConfig as the read side — backends that need richer config read their own env (the established seam convention; see chassis/continuation/factory.go and chassis/trace/factory.go).

type Source

type Source interface {
	// Poll returns events with ControlVersion > sinceControlVersion,
	// sorted ascending by ControlVersion. An empty slice means "nothing
	// new" (not an error). Implementations must be cheap to call on a
	// timer and must not block beyond ctx.
	Poll(ctx context.Context, sinceControlVersion uint64) ([]controlevent.Event, error)

	// Name is the backend identity (for logs).
	Name() string
}

Source yields control events strictly after a cursor position.

func Open

func Open(name string, cfg SourceConfig) (Source, error)

Open constructs the named backend. Unknown name is a startup error listing what is available.

type SourceConfig

type SourceConfig struct {
	FileDir string
}

SourceConfig carries backend-selecting options resolved from chassis config. The file backend uses FileDir. Additional backends may extend this struct with their own fields; existing backends and callers are unaffected by added fields.

Directories

Path Synopsis
Package filesource is the local-directory feed source: zero infrastructure, directly inspectable, useful for development and as a drop point a sidecar can write into.
Package filesource is the local-directory feed source: zero infrastructure, directly inspectable, useful for development and as a drop point a sidecar can write into.
Package nop is the disabled feed source + sink: the single-node default.
Package nop is the disabled feed source + sink: the single-node default.

Jump to

Keyboard shortcuts

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