com.worxbend.kernel.event

Members list

Type members

Classlikes

object AttrValue

Attributes

Companion
enum
Supertypes
trait Sum
trait Mirror
class Object
trait Matchable
class Any
Self type
AttrValue.type
enum AttrValue

The CloudEvents attribute type system, as an ADT rather than Map[String, String].

The CloudEvents attribute type system, as an ADT rather than Map[String, String].

The spec defines exactly six attribute types (Boolean, Integer, String, Binary, URI, URI-Reference, Timestamp — the two URI forms share a Scala representation here). Collapsing them to strings would be lossy in the direction that matters: a producer that sets sequence as an Integer and a consumer that reads it as a string disagree about ordering, and nothing in the pipeline would notice.

Other is not in the ADR. It exists because losslessness is a hard requirement and the JSON format cannot be made total without it: a non-integral number, an array or an object appearing as an extension value is out of spec, but dropping it — or failing the whole event because of it — loses data this system promised to keep. Other carries such a value verbatim so it round-trips and is still visible in search.

Attributes

Companion
object
Supertypes
trait Enum
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
final class Binary

An immutable byte string with structural equality.

An immutable byte string with structural equality.

ADR §4.1 spells the binary payload IArray[Byte]. That type is an opaque alias over Array, so it inherits Array's reference equality: two IArrays with identical contents are !=. Threading that through Payload and Envelope would make every derived equals wrong — and the things this build compares envelopes for are exactly the load-bearing ones: codec round-trip properties, (source, id) deduplication and DLQ replay identity. A defect there is silent, so the representation is wrapped instead.

toIArray gives back the ADR's view for consumers that want it. The array is copied on the way in and on the way out, which is the price of immutability that actually holds.

Attributes

Companion
object
Supertypes
class Object
trait Matchable
class Any
object Binary

Attributes

Companion
class
Supertypes
class Object
trait Matchable
class Any
Self type
Binary.type
object ContentType

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
final case class Envelope(id: EventId, source: Source, eventType: EventType, time: Option[OffsetDateTime], subject: Option[Subject], dataContentType: Option[ContentType], schema: Option[SchemaRef], extensions: Map[String, AttrValue], payload: Payload)

A CloudEvents 1.0 event, as this system's domain type.

A CloudEvents 1.0 event, as this system's domain type.

The SDK's io.cloudevents.CloudEvent is an adapter and lives in modules/eventing only (ADR §4): it is a Java interface with nullable getters, a throwing mutable builder and a byte-oriented data model, none of which pattern-matches. This type is the one the three services agree on.

Two deviations from ADR §4.1, both forced by the losslessness requirement:

  • time is Option[OffsetDateTime]. The ADR declares it required; the spec makes it OPTIONAL, and inventing a time for an event that did not carry one would corrupt the partition it lands in (ADR §5). It remains OffsetDateTime and never Instant, so the producer's local offset survives.
  • dataContentType is an explicit attribute. Payload.Opaque also carries a media type, but that field describes the bytes for consumers holding only a Payload (notably Observation.Unrecognised); the envelope attribute is the single source of truth for the wire, and canonical reconciles the two.

Unknown context attributes land in extensions and unknown payload shapes in Payload.Structured, so an event this build has never seen still parses, still persists, and still comes back out unchanged.

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
object Envelope

Attributes

Companion
class
Supertypes
trait Product
trait Mirror
class Object
trait Matchable
class Any
Self type
Envelope.type
object EventId

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
EventId.type
object EventType

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
EventType.type
object EventTypes

The reverse-DNS type strings this build recognises.

The reverse-DNS type strings this build recognises.

Versions are absent by design: a type string that carries its version forks the registry on every additive schema change and turns "all telemetry" into a prefix match. Versioning hangs off dataschema (ADR §4.2).

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
EventTypes.type
object Observation

Attributes

Companion
enum
Supertypes
trait Sum
trait Mirror
class Object
trait Matchable
class Any
Self type

The strongly typed reading refined out of an Envelope.

The strongly typed reading refined out of an Envelope.

Unrecognised is not an error case, it is the total fallback: without it, persistence and the UI would depend on this enum being complete, and a firmware update that ships a new event type would start dropping data (ADR §4.2). Every Unrecognised carries the payload and, when the type was known but the payload did not fit, a reason — that pair is what the event.unrecognised{type,reason} counter is tagged with, and it is the only way to tell a new device apart from a broken decoder.

Attributes

Companion
object
Supertypes
trait Enum
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
object Observed

Attributes

Companion
class
Supertypes
trait Product
trait Mirror
class Object
trait Matchable
class Any
Self type
Observed.type
final case class Observed(envelope: Envelope, observation: Observation)

An envelope paired with its refinement.

An envelope paired with its refinement.

Refinement is lossy by construction — Unrecognised keeps the payload but not the source, extensions or time — so anything that both routes on the observation and persists the event carries this pair rather than choosing one.

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
object Payload

Attributes

Companion
enum
Supertypes
trait Sum
trait Mirror
class Object
trait Matchable
class Any
Self type
Payload.type
enum Payload

The data slot of a CloudEvent.

The data slot of a CloudEvent.

JSON Format 1.0 offers exactly three shapes and they are mutually exclusive on the wire: an inline data JSON value, a base64 data_base64 string, or neither. Modelling that as an ADT rather than as two nullable fields makes "both present" — which the spec forbids — unrepresentable rather than a validation rule someone forgets.

Structured holds an arbitrary Json, not a decoded domain type. That is the load-bearing choice of ADR §4.2: an event whose shape this build has never seen still parses, still persists and still renders.

Attributes

Companion
object
Supertypes
trait Enum
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
object SchemaRef

Attributes

Companion
class
Supertypes
trait Product
trait Mirror
class Object
trait Matchable
class Any
Self type
SchemaRef.type
final case class SchemaRef(uri: URI)

The CloudEvents dataschema attribute.

The CloudEvents dataschema attribute.

ADR §4.1 declares SchemaRef(uri, name, version) with name and version required. That cannot be honoured literally without losing data: dataschema is any URI, and one that does not end in …// would have nowhere to go. Since ADR §4.2 also requires the raw URI to be stored verbatim, the URI is made the single field and name/version become derived views. Equality is therefore on the URI alone, which is what makes the envelope round-trip exact.

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
object SemVer

Attributes

Companion
class
Supertypes
trait Product
trait Mirror
class Object
trait Matchable
class Any
Self type
SemVer.type
final case class SemVer(major: Int, minor: Int, patch: Int) extends Ordered[SemVer]

A semantic version, used to key the Observation decoder registry.

A semantic version, used to key the Observation decoder registry.

Only major participates in dispatch (ADR §4.2): minor and patch bumps are required to be additive, so a decoder registered for major 1 must keep working against 1.7.3. Keeping the full triple anyway means a stored event can still be explained precisely years later.

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
trait Ordered[SemVer]
trait Comparable[SemVer]
class Object
trait Matchable
class Any
Show all
object Source

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Source.type
object Subject

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Subject.type
object Topics

Kafka topic names and the key functions that go with them (ADR §4.3).

Kafka topic names and the key functions that go with them (ADR §4.3).

These live in the kernel rather than in each service's configuration because a typo in a topic name produces a consumer that starts cleanly and receives nothing — the least debuggable failure in the system. Three services reading one constant cannot disagree.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Topics.type

Types

opaque type ContentType

CloudEvents datacontenttype — an RFC 2046 media type describing data.

CloudEvents datacontenttype — an RFC 2046 media type describing data.

Attributes

opaque type EventId

CloudEvents id — unique per producer within the scope of a Source.

CloudEvents id — unique per producer within the scope of a Source.

Modelled as opaque type … <: String rather than a wrapper class: the upper bound gives one-way assignability, so an EventId flows into a JDBC setter, a circe encoder or a log statement with zero allocation and zero unwrapping, while a Source can still never be passed where an EventId is expected. That asymmetry is the whole point — (source, id) is the deduplication key of the entire pipeline, and silently swapping the two would produce a system that looks correct and deduplicates nothing.

Attributes

opaque type EventType

CloudEvents type — reverse-DNS, versioned by dataschema rather than by a suffix on this string.

CloudEvents type — reverse-DNS, versioned by dataschema rather than by a suffix on this string.

See ADR §4.2: putting the version in the type string forks the registry on every additive change and makes "give me all telemetry" a prefix match instead of an equality match.

Attributes

opaque type Source

CloudEvents source — an RFC 3986 URI-reference identifying the producing context.

CloudEvents source — an RFC 3986 URI-reference identifying the producing context.

Kept as a string rather than a java.net.URI because the wire form must survive verbatim: URI normalises nothing on construction but toString is only guaranteed to reproduce the input for URIs built from a string, and the dimension tables key on the exact bytes the producer sent.

Attributes

opaque type Subject

CloudEvents subject — the device or entity within the Source.

CloudEvents subject — the device or entity within the Source.

This is half of the Kafka partition key (Envelope.partitionKey), which is why it is a distinct type: appending the wrong attribute to the key silently destroys per-device ordering, and that failure is invisible until someone plots a device timeline months later.

Attributes