Structuring events in a messaging system


This post describes some general principles that can be used to create an event structure for a messaging system. They can be applied to any practical domain assuming that “events” concept is part of it.

What is an event?

To better understand the structure of events it’s good to know what is an event in the context of some messaging system. In general we can classify any message as one of the following.

  • Task (or Job or Command) message. By sending this message sender specifically tells receiver what need to be done.

  • Data (or Document) message. It contains some chuck of information that makes sense for a given system. Sender transfer this data to receiver buy does not specify what need to be done.

  • Event message. This is a notification about some changes in the system.
    Send just notifies receiver about this change. As with a Data message it does not tell how receiver should react.

In some cases the distinction between Data and Event messages is blurry. Events can contain entire objects, typically for easier processing on the receiver’s side. What’s more important is that both data and events just provide some information without specific instructions about what need to be done with it.

This is a great architectural approach because it detaches places where change happens from an actual processing of this change. This make systems more flexible and transparent. For example we can change processing steps, or add some parallel processing without a need to change code (or even know about it) that produces an event.

So further discussion will be focused on Event messages structure. Other message types require slightly different approach.

Generalized event structure

Each event describes some change(s) in the system. Event structure can be seen as a series of answers to the following basic questions about the change.

  • Who?
  • What?
  • How?
  • When?
  • Where?

The answer to question “Who?” tells us about an actor who performed the change. It can be a user or some system process.

Answer to “What?” describes an object that was changed.

Answer to “How?” tells us about specifics of this change, or how the object was affected by an actor.

Answer to “When?” specify time parameters of the change, typically it say when the change was made (timestamp). In some case time aspect of an event requires additional details such as duration or specification of time intervals.

Answer to “Where?” specify the exact location of this event. It can be a device, process, IP address, web site, UI screen and so on.

In addition to these questions it is necessary sometime to provide additional useful data, or we may call it extra context of the event.

Versioning

Events generated by the system are often placed into long term storage. They can be later retrieved for further analysis. Another factor we need to consider is that things are changing over time. It means developers improve event format, so to make later analysis easier it’s a really good idea to attach versioning information to every event.

The most simple way to do it is to add integer attribute containing event version number which will be “1” initially, for example v=1. Increment it for each future format version. It’s also important to describe format somewhere in the system documentation.

Example

Following example specifies event structure for imaginary video hosting platform. Let’s say we want to capture events related to users behavior such as browsing catalog, playing movies, likes, dislikes, etc.

{
  /* Event metadata *
  v: 1,

  /* Who? */
  actor_id: 'user_1865',

  /* What? */
  object_id: 'movie_2471',

  /* How? */
  type: 'liked',

  /* When? */
  ts: '2020-04-...',

  /* Where? */
  ip: '8.9.9.8',

  /* Extra context */
  extra: {
    ui: {
      screen: 'movie_details'
    }
  }
}

This event basically says “user_1865 liked movie_2471 at 2020-04-… from IP 8.9.9.8 on movie_details screen”. In this case part of location data ui.screen moved down to extra structure because it’s not present for all event types. The decision here is to form event structure core and move optional parts into an extra map. This usually make events storage and processing easier.

However there is no right or wrong way here, everything depends on current system needs and restrictions. At the same time above principles and basic questions provide a guideline or framework for building robust, useful and flexible event structures.