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 ¶
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.
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.
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. |