Documentation
¶
Overview ¶
Package eventing implements funcd eventing (ADR-0023, reshaped by ADR-0108): a typed CloudEvents v1.0 envelope, an EventSource reconciler that registers a `timer:` source's NAMED events, and — on each firing — PUBLISHES a named CloudEvent onto a Publisher seam (the in-process Fanout) the F69 Sensor subscribes to. It owns only KindEventSource (one-reconciler-per-gvk, ADR-0015); ticking is a side Run loop, not the reconciler. The action side (invoke a function / start a workflow) is the Sensor (ADR-0109); the webhook source kind, cron schedules, and bus-backed delivery are documented deferrals.
Index ¶
- func ParseSourceURI(uri string) (ns v1.NamespaceName, source v1.ObjectName, ok bool)
- func SourceURI(ns v1.NamespaceName, source v1.ObjectName) string
- type BlobEventData
- type BlobWatcher
- type BucketLister
- type CloudEvent
- type Cursor
- type Deps
- type Fanout
- type KVWatermark
- type MemWatermark
- type Publisher
- type Source
- type Watermark
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ParseSourceURI ¶
func ParseSourceURI(uri string) (ns v1.NamespaceName, source v1.ObjectName, ok bool)
ParseSourceURI is the inverse of SourceURI: it recovers (namespace, source) from a CloudEvent's `source` field so a subscriber can route by structured key (ADR-0108). ok=false for a foreign URI.
func SourceURI ¶
func SourceURI(ns v1.NamespaceName, source v1.ObjectName) string
SourceURI is the canonical CloudEvent `source` for an EventSource (ADR-0108).
Types ¶
type BlobEventData ¶
type BlobEventData struct {
Bucket string `json:"bucket"`
Key string `json:"key"`
Size int64 `json:"size"`
Version string `json:"version"`
Time time.Time `json:"time"`
}
BlobEventData is the `data` payload of a blob CloudEvent (ADR-0119, F83): what landed under a watched Bucket prefix, for a Sensor to project (e.g. `${{ event.data.key }}`). Version is a (ModTime,Size) fingerprint of the observed object version — NOT a content ETag (blob.Attributes exposes none in V1).
type BlobWatcher ¶
type BlobWatcher struct {
// contains filtered or unexported fields
}
BlobWatcher polls each registered blob EventSource, diffs each prefix against the persisted Watermark, and publishes one named CloudEvent per new object through the existing ADR-0108 Publisher (ADR-0119). Registration is driven by the KindEventSource reconciler (ADR-0015 one-per-gvk); Run is a side loop started by the pkg/funcd lifecycle, mirroring eventing.Source.Run for timers. Advance-on-emission gives at-least-once: a crash between publish and save re-emits next poll (the Sensor/ADR-0118 absorb it).
func NewBlobWatcher ¶
func NewBlobWatcher(lister BucketLister, pub Publisher, marks Watermark, interval time.Duration, log *slog.Logger) (*BlobWatcher, error)
NewBlobWatcher builds the watcher. lister/publisher/marks are required; interval ≤ 0 ⇒ the 15s default.
func (*BlobWatcher) ActiveWatches ¶
func (w *BlobWatcher) ActiveWatches() int
ActiveWatches reports the number of registered named blob events (observability + the reconcile scenario).
func (*BlobWatcher) Deregister ¶
func (w *BlobWatcher) Deregister(ns v1.NamespaceName, source v1.ObjectName)
Deregister removes every named event of one EventSource (delete / kind-change).
func (*BlobWatcher) Register ¶
func (w *BlobWatcher) Register(ns v1.NamespaceName, source v1.ObjectName, bs *v1.BlobSource)
Register (re)registers every named event of a blob source and prunes events dropped from the spec — the reconciler calls it on a Ready blob EventSource (ADR-0119).
type BucketLister ¶
type BucketLister interface {
List(ctx context.Context, ns v1.NamespaceName, bucket v1.ObjectName, prefix string) ([]blob.Attributes, error)
}
BucketLister resolves a Bucket resource to its scoped blob listing surface (ADR-0007/0080) and lists a prefix over it. The V1 driver reuses pkg/funcd's s3BucketFor resolver — the SAME blob.Bucket view external S3-frontend writes land in — so detection is writer-agnostic (it depends only on List). A missing Bucket resolves as fault.NotFound.
type CloudEvent ¶
type CloudEvent struct {
SpecVersion string `json:"specversion"`
ID string `json:"id"`
Source string `json:"source"` // funcd://<ns>/eventsource/<name>
Type string `json:"type"` // the event name (ADR-0108)
Time time.Time `json:"time"`
DataContentType string `json:"datacontenttype,omitempty"`
Data json.RawMessage `json:"data,omitempty"`
}
CloudEvent is a CloudEvents v1.0 envelope serialized in the JSON event format. Hand-defined (no cloudevents/sdk-go); a later SDK swap stays behind this type.
func NewBlobEvent ¶
func NewBlobEvent(ns v1.NamespaceName, source, event v1.ObjectName, d BlobEventData) (CloudEvent, error)
NewBlobEvent builds a named CloudEvent for a landed object (ADR-0119): the same envelope as NewNamedEvent (source URI carries ns+source, type carries the event name), but `data` is the object descriptor instead of the timer's empty `{}`. It flows the unchanged Fanout → Sensor path.
func NewNamedEvent ¶
func NewNamedEvent(ns v1.NamespaceName, source, event v1.ObjectName) (CloudEvent, error)
NewNamedEvent builds a well-formed named CloudEvent for one event of an EventSource (ADR-0108): the `source` URI carries the namespace + source name, `type` carries the event name. A timer event has an empty `{}` payload. The id is a fresh random hex string (unique per call).
type Cursor ¶
type Cursor struct {
MaxModTime time.Time `json:"maxModTime"`
KeysAtMax []string `json:"keysAtMax"`
}
Cursor is the compact, bounded watermark for one named blob event (ADR-0119): the newest ModTime seen and the key set AT that timestamp (the tie-break set). A listed object is NEW iff its ModTime > MaxModTime, or (ModTime == MaxModTime and its key is not in KeysAtMax). KeysAtMax resets when MaxModTime advances, so it stays bounded to the objects sharing the newest timestamp — enough for Created-only dedup.
type Deps ¶
type Deps struct {
Store store.Store // required
Publisher Publisher // where a firing emits its named CloudEvent (required)
Blob *BlobWatcher // ADR-0119: the poll watcher a `blob:` source registers on; nil ⇒ no blob support
Logger *slog.Logger // default slog.Default()
}
Deps configures the eventing Source (internal component, ADR-0002 §1; reshaped by ADR-0108, extended by ADR-0119).
type Fanout ¶
type Fanout struct {
// contains filtered or unexported fields
}
Fanout is the in-process Publisher driver (ADR-0108): a fired CloudEvent is delivered to every live subscriber whose (namespace, source, event) key matches it. Routing derives that key from the envelope — ParseSourceURI(ev.Source) + ev.Type — the inverse of NewNamedEvent, so the URI is the single canonical name↔key mapping. The F69 Sensor subscribes; a firing to no subscriber is a no-op. Delivery is non-durable (a fire while a subscriber is down is lost); a bus-backed Publisher is a V2 swap.
func (*Fanout) Publish ¶
func (f *Fanout) Publish(ctx context.Context, ev CloudEvent) error
Publish delivers ev to every subscriber of its derived (ns, source, event) key. A source URI that is not a funcd EventSource URI is dropped (never an error) — the seam only carries funcd named events.
func (*Fanout) Subscribe ¶
func (f *Fanout) Subscribe(ns v1.NamespaceName, source, event v1.ObjectName, fn func(context.Context, CloudEvent)) (cancel func())
Subscribe registers fn for the named event (ns, source, event); the returned cancel deregisters it.
type KVWatermark ¶
type KVWatermark struct {
// contains filtered or unexported fields
}
KVWatermark is the V1 Watermark driver (ADR-0119): one small JSON Cursor per (ns, source, event) over the in-tree kvstore.KV substrate — durable get/put with its own backup path, so no second persistence mechanism. A missing record loads as the zero Cursor (nothing seen yet).
func NewKVWatermark ¶
func NewKVWatermark(kv kvstore.KV) (*KVWatermark, error)
NewKVWatermark builds the KV-backed Watermark driver over kv (required).
func (*KVWatermark) Load ¶
func (w *KVWatermark) Load(ctx context.Context, ns v1.NamespaceName, source, event v1.ObjectName) (Cursor, error)
Load returns the persisted Cursor for (ns, source, event); a missing record is the zero Cursor (no error).
func (*KVWatermark) Save ¶
func (w *KVWatermark) Save(ctx context.Context, ns v1.NamespaceName, source, event v1.ObjectName, c Cursor) error
Save persists the advanced Cursor for (ns, source, event), overwriting the prior record.
type MemWatermark ¶
type MemWatermark struct {
// contains filtered or unexported fields
}
MemWatermark is an in-process Watermark driver (ADR-0119): a mutex-guarded map of cursors. It is the non-durable sibling of KVWatermark — used by tests and any deployment that does not need cross-restart dedup. Held to the same Watermark contract.
func NewMemWatermark ¶
func NewMemWatermark() *MemWatermark
NewMemWatermark builds an empty in-memory Watermark driver.
func (*MemWatermark) Load ¶
func (m *MemWatermark) Load(_ context.Context, ns v1.NamespaceName, source, event v1.ObjectName) (Cursor, error)
Load returns the stored Cursor for (ns, source, event); an absent key is the zero Cursor.
func (*MemWatermark) Save ¶
func (m *MemWatermark) Save(_ context.Context, ns v1.NamespaceName, source, event v1.ObjectName, c Cursor) error
Save stores the Cursor for (ns, source, event) (a defensive copy of the slice).
type Publisher ¶
type Publisher interface {
Publish(ctx context.Context, ev CloudEvent) error
}
Publisher is the delivery seam a Source emits named CloudEvents to (ADR-0108). The V1 driver is the in-process Fanout (fanout.go) the F69 Sensor subscribes to; a bus-backed driver is a V2 swap. Emitting to nobody is a no-op by design (an EventSource with no Sensor yet is valid).
type Source ¶
type Source struct {
// contains filtered or unexported fields
}
Source is the EventSource reconciler + the registered named-event timer set. A firing PUBLISHES a named CloudEvent (ADR-0108); the action side (invoke a function / start a workflow, and the Invocation record) is the F69 Sensor (ADR-0109). The Source no longer invokes.
func (*Source) ActiveTimers ¶
ActiveTimers reports the number of registered named-event timers (observability; a status/metrics surface and the reconcile scenario both read it).
func (*Source) Fire ¶
func (s *Source) Fire(ctx context.Context, ns v1.NamespaceName, source, event v1.ObjectName) error
Fire performs one deterministic tick of a named event: build its CloudEvent and publish it. A published-to-nobody event is a no-op (no Sensor subscribed yet) — never an error.
func (*Source) Reconcile ¶
func (s *Source) Reconcile(ctx context.Context, req controller.Request) (controller.Result, error)
Reconcile owns KindEventSource (ADR-0108): it registers every named event of a `timer:` source (→ Ready), deregisters on delete, and registers nothing for a source with no timer kind.
type Watermark ¶
type Watermark interface {
Load(ctx context.Context, ns v1.NamespaceName, source, event v1.ObjectName) (Cursor, error)
Save(ctx context.Context, ns v1.NamespaceName, source, event v1.ObjectName, c Cursor) error
}
Watermark persists per-event dedup state so a re-list and a restart never re-emit a seen object (ADR-0119). The V1 driver stores one JSON record per (ns, source, event) over internal/kvstore.KV.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package deadletter is the eventing dead-letter queue PORT (ADR-0118, F85): the durable park for a Sensor action-delivery that failed past the bounded retry cap.
|
Package deadletter is the eventing dead-letter queue PORT (ADR-0118, F85): the durable park for a Sensor action-delivery that failed past the bounded retry cap. |
|
badger
Package badger is the dead-letter-queue deadletter driver (ADR-0118), backed by Badger v4 in a DEDICATED instance (never the metastore).
|
Package badger is the dead-letter-queue deadletter driver (ADR-0118), backed by Badger v4 in a DEDICATED instance (never the metastore). |
|
memory
Package memory is the in-memory deadletter.Store driver (ADR-0118): a small pure-Go map with no files, for cross-platform tests and the InMemory preset.
|
Package memory is the in-memory deadletter.Store driver (ADR-0118): a small pure-Go map with no files, for cross-platform tests and the InMemory preset. |