Anatomy of an event

2 min read
On trails:EDAstep 3/8

An event has two parts: an envelope of metadata that every event carries in the same shape, and a payload with the business facts of this one event. The envelope lets infrastructure route, deduplicate and trace messages without understanding what is inside them.

In code

envelope.csC#
public sealed record EventEnvelope<T>(    Guid MessageId,    string MessageType,    DateTimeOffset OccurredOn,    int Version,    Guid CorrelationId,    Guid? CausationId,    T Payload); public sealed record OrderLine(string Sku, int Quantity); public sealed record OrderPlaced(    Guid OrderId,    Guid CustomerId,    decimal Total,    IReadOnlyList<OrderLine> Lines); var placed = new EventEnvelope<OrderPlaced>(    MessageId: Guid.NewGuid(),    MessageType: "OrderPlaced",    OccurredOn: DateTimeOffset.UtcNow,    Version: 1,    CorrelationId: checkoutId,    CausationId: null,    Payload: new OrderPlaced(orderId, customerId, 59.90m, lines));

The envelope

  • MessageId identifies this one message. Consumers use it to spot a duplicate, see idempotent consumersIdempotent consumersA consumer that gives the same result whether a message arrives once or five times.Opens in a new tab.
  • MessageType names the event, such as OrderPlaced. Routing and deserialization start from it.
  • OccurredOn is when the thing happened, which can differ from when the message was sent.
  • Version is the version of the payload shape, so consumers can cope with change, see event versioningEvent versioningChange an event's shape by adding to it, and run a second version beside the first when you must break it.Opens in a new tab.
  • CorrelationId is shared by every message that belongs to one original request, here the whole checkout.
  • CausationId is the MessageId of the message that directly caused this one. Together with the correlation id it lets a trace be rebuilt, see observing event flowsObserving event flowsFollowing one order through several services, and the three queue numbers that warn first.Opens in a new tab.

The CloudEventsA vendor-neutral specification for describing event data. specification standardizes a similar envelope. It requires id, source, specversion and type, and defines optional attributes such as time, subject and datacontenttype. The names differ from the record above, but the roles match, so there is no need to invent a format when a standard exists.

The payload

The payload carries what consumers need about the fact. OrderPlaced holds the order id, the customer, the total and the lines. How much to put in is a real choice: a small event with only ids makes consumers ask back for details, a large one copies data into every consumer. See event notification vs state transferEvent notification vs state transferA thin event says that something happened. A fat event also carries the data.Opens in a new tab.

The catch

Every subscriber can read the whole event. Events are often visible to components that do not need them, so personal data, secrets and card details do not belong in the payload. Microsoft’s guide recommends thinking about what an event exposes with an assume-breach mindset.


Sources