event

package
v0.10.0 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package event defines the CloudEvents 1.0 envelope and the types a domain uses to raise its events.

The package exports:

  • SpecVersion, the CloudEvents version it implements, and Event, one event's context attributes and data, with Event.Validate, which reports every way an event breaks the specification
  • Header, a message's headers, and Encode and Decode, which map an Event to and from binary content mode
  • EventKind, one event a domain raises, its type paired with the Go type of its data; Define, which declares one, and CheckType, the rule its type follows; EventKind.Type, and EventKind.Raise, which adds an event of the kind to a Queue
  • Queue, the events one command raises, with Queue.Events, a copy of them, and Queue.Err, every failure a raise held
  • Sink, what writes stamped events into a transaction, and Recorder, which emits a command's events through one, with NewRecorder, which returns one, and Recorder.Emit, which wraps a command's body into the function a transaction runs
  • Option, which configures a Recorder, with Clock, the time it stamps, and IDs, how it mints an event id
  • Permanent, which marks a handler's error as one redelivery cannot fix, and IsPermanent, which reports the mark

Envelope

An Event carries the context attributes a service sets, and Encode and Decode map it to and from binary content mode: each attribute is a ce-prefixed header, datacontenttype is the content-type header, and the data travels as the message body. Header is a plain map, so it converts to a NATS or HTTP header without this package importing either.

Raising and emitting

A domain raises events, and a recorder emits them. A domain declares each event it raises as an EventKind, which pairs the event type with the Go type of its data:

var Started = event.Define[StartedData]("exercise.started")

A command raises its events into a Queue while it runs, and a Recorder emits them through its Sink into the command's own transaction, so an event is emitted only in the transaction of the command that makes it true. Recorder.Emit states when it stamps and writes.

The transaction is a type parameter, so this package names no database. The composition root fixes the type when it builds the recorder over a sink, such as an outbox's, and passing a pool where the sink expects its transaction type fails to compile.

Handling

A handler that must never see an event again wraps its error with Permanent.

The package uses the standard library alone.

Index

Constants

View Source
const SpecVersion = "1.0"

SpecVersion is the CloudEvents specification version this package implements.

Variables

This section is empty.

Functions

func CheckType

func CheckType(t string) error

CheckType reports whether t is an event type a broker can route: one or more tokens separated by '.', none of them empty, with no whitespace, '*', or '>'. The rule is a subject's, so a provider can route on the type itself, and it admits the reverse-DNS types CloudEvents recommends, such as "lab.grant.approved".

func IsPermanent

func IsPermanent(err error) bool

IsPermanent reports whether any error in err's tree was marked by Permanent.

func Permanent

func Permanent(err error) error

Permanent marks err as a handler failure that must never be redelivered; the provider terminates the delivery instead. The mark survives further wrapping, and errors.Is and errors.As still reach err. Permanent(nil) is nil.

Types

type Event

type Event struct {
	ID              string
	Source          string
	Type            string
	Subject         string
	DataContentType string
	DataSchema      string
	Time            time.Time
	Data            []byte
	Extensions      map[string]string
}

Event is one CloudEvents 1.0 event. ID, Source, and Type are required; the specversion is always SpecVersion and is not a field. A zero Time and an empty Subject, DataContentType, or DataSchema are absent attributes. Extensions holds the extension attributes, such as traceparent, keyed by name.

func Decode

func Decode(h Header, body []byte) (Event, error)

Decode reads an event from binary content mode. Header names match case-insensitively, so a canonicalized HTTP header decodes too, and a lowercase name wins over another spelling of it. Any ce-prefixed header that is not a context attribute is an extension. The time attribute is parsed as RFC 3339 and returned in UTC, whatever offset it was written with. The result must carry specversion 1.0 and pass Event.Validate.

func (Event) Validate

func (e Event) Validate() error

Validate reports every way e breaks the specification: a missing required attribute, or an extension name that is empty, is not lowercase alphanumeric, or shadows a context attribute. The specification's 20-character limit on names is a recommendation, so it is not enforced.

type EventKind

type EventKind[T any] struct {
	// contains filtered or unexported fields
}

EventKind is one event a domain raises: its type, and T, the Go type of its data. A domain declares its kinds with Define, so the type and T cannot drift apart at a call site.

func Define

func Define[T any](typ string) EventKind[T]

Define declares the event kind of type typ, whose data is a T encoded as JSON. A type that breaks CheckType is a declaration defect, so Define panics; when the kind is a package variable, it panics at the package's initialization.

func (EventKind[T]) Raise

func (k EventKind[T]) Raise(q *Queue, subject string, data T)

Raise adds an event of this kind about subject, carrying data, to q. The event has no id, source, or time until the recorder stamps it. An empty subject leaves the attribute absent. A failure to encode data is held on q, and fails the command when the recorder emits.

func (EventKind[T]) Type

func (k EventKind[T]) Type() string

Type returns the kind's event type.

type Header map[string][]string

Header is a message's headers in binary content mode. Its shape matches nats.Header and http.Header. Values are written as given: a provider whose protocol binding requires encoding them, such as HTTP's percent-encoding, encodes them itself.

func Encode

func Encode(e Event) (Header, []byte, error)

Encode maps a valid e to binary content mode: the headers and the body. The time attribute is written in UTC, as RFC 3339 with nanoseconds.

type Option

type Option func(*options)

Option configures a Recorder.

func Clock

func Clock(now func() time.Time) Option

Clock sets the time a recorder stamps; the default is time.Now.

func IDs

func IDs(id func() string) Option

IDs sets how a recorder mints an event id; the default is a version 7 UUID, which orders by time.

type Queue

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

Queue holds the events one command raises, in the order it raises them. Recorder.Emit gives each run of a command a fresh queue and emits it when the command succeeds; a command never emits a queue itself.

func (*Queue) Err

func (q *Queue) Err() error

Err returns every failure a raise held, or nil.

func (*Queue) Events

func (q *Queue) Events() []Event

Events returns a copy of the queued events, unstamped, so a test can read what a command raised.

type Recorder

type Recorder[Tx any] struct {
	// contains filtered or unexported fields
}

Recorder emits the events a command raises into the command's transaction, stamped with the id, source, and time the domain never sets. The composition root builds one per service and injects it into each domain.

func NewRecorder

func NewRecorder[Tx any](sink Sink[Tx], source string, opts ...Option) *Recorder[Tx]

NewRecorder builds the recorder that writes through sink and stamps every event with source, the service's own URI-reference. Source is one value for the whole service, never a replica's, because a consumer deduplicates on the source and id together. A nil sink or an empty source is a wiring defect and panics.

func (*Recorder[Tx]) Emit

func (r *Recorder[Tx]) Emit[R any](ctx context.Context, fn func(Tx, *Queue) (R, error)) func(Tx) (R, error)

Emit wraps fn, a command's body, into the function a transaction runs, such as sqlate's Transact. The body runs on the transaction with a fresh Queue. When it returns an error, Emit returns it and writes nothing. When it succeeds, Emit stamps each queued event, its time the clock's in UTC, and writes them, in the order raised, through the sink into the same transaction, before the caller commits. A failed raise or write fails the command, so the transaction rolls back with its state and its events together. Emit neither begins nor ends the transaction; the code that began it ends it. ctx is the context of the write.

type Sink

type Sink[Tx any] interface {
	Write(ctx context.Context, tx Tx, es ...Event) error
}

Sink writes stamped events into a transaction of type Tx, the one the command that raised them runs in. An outbox is the sink a composition root builds a recorder over; it writes each event as a row the relay publishes after the transaction commits.

Jump to

Keyboard shortcuts

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