Documentation
¶
Overview ¶
Package eventlog defines retained, independently scoped event logs and consumer-owned checkpoints. It does not register consumers or deliver events.
Index ¶
Constants ¶
const ( DefaultLimit = 100 MaxLimit = 500 MaxTypes = 100 DefaultRetention = 90 * 24 * time.Hour )
Variables ¶
Functions ¶
This section is empty.
Types ¶
type Consumer ¶
type Consumer struct {
Reader Reader
Subscription Subscription
Limit int
Load func(ctx context.Context, key string) (string, error)
Commit func(ctx context.Context, key, previous string, page Page) error
}
Consumer polls one page. The owner schedules retries and polling. Load returns an empty cursor only for a new subscription. Commit must atomically apply idempotent effects and persist page.NextCursor, conditional on the checkpoint still equaling previous (or serialize consumers). It must commit empty pages, too. With external effects, scope each event ID by subscription source and scope when forming idempotency keys before saving. Neither Load nor Commit is producer-side state.
type CursorCodec ¶
CursorCodec allows a product to retain its already-issued cursor envelope during adoption. Decode must reject malformed/oversized input, unsupported versions and negative positions. Missing boundaries must never be invented.
type Event ¶
type Event struct {
ID string `json:"id"`
// Source is product-owned provenance (for example host or notification).
// It is not the log namespace and is not a global deduplication key.
Source string `json:"source"`
Scope string `json:"scope"`
Type string `json:"type"`
Version int `json:"version"`
OccurredAt time.Time `json:"occurred_at"`
RecordedAt time.Time `json:"recorded_at"`
Subject Subject `json:"subject"`
Data json.RawMessage `json:"data"`
}
Event is a product-owned fact. IDs are opaque; only cursors define order. RecordedAt is storage time; OccurredAt may describe an earlier domain event.
type JSONCursor ¶
type JSONCursor struct{}
func (JSONCursor) Encode ¶
func (JSONCursor) Encode(c Cursor) string
type Log ¶
type Log struct {
// NormalizeQuery preserves historical filter semantics during migration.
// Nil uses Normalize. Legacy normalizers must retain bounded input and limits.
NormalizeQuery func(Query) (Query, error)
// SkipFloorBoundary preserves legacy logs that never stored a pruned boundary ID.
// Only enable for an existing cursor contract that already omitted this check.
SkipFloorBoundary bool
// Source names the product/log namespace, independent of Event.Source.
Source string
Scope string
Retention time.Duration
Now func() time.Time
Codec CursorCodec
ReadSnapshot func(context.Context, func(Snapshot) error) error
}
Log centralizes paging, retention and cursor validation over product storage. A codec is optional for new logs; existing logs supply their legacy codec. ReadSnapshot must run the callback once using a single committed snapshot.
type Position ¶
Position and Stream describe storage state within one consistent snapshot. Floor includes records expired by read-time retention even before pruning.
type Query ¶
type Reader ¶
Reader is already bound to an authorized source and scope. Embedded and HTTP product clients implement this same interface; authentication stays with them.
type ReaderFunc ¶
func (ReaderFunc) ListEvents ¶
type Snapshot ¶
type Snapshot interface {
Stream(context.Context, time.Time) (Stream, error)
Boundary(context.Context, int64) (string, error)
Events(context.Context, int64, []string, int) ([]Record, error)
}
Snapshot must expose committed rows from one repeatable-read snapshot. Events returns strictly increasing positions above after, filtered by exact types (empty means all), with at most limit records. Head's Floor is the last expired position at cutoff. Legacy storage with nonmonotonic RecordedAt must compute the retained prefix floor and additionally exclude expired rows in Events.
type Subscription ¶
Subscription identifies a consumer checkpoint. Changing any field selects a different checkpoint. Source names the deployment/product log, not Event.Source provenance. A filter change must not reuse the old cursor.
func (Subscription) Key ¶
func (s Subscription) Key() (string, error)