telestion-architecture

ADR-0006: NATS message format

Date: 2023-01-24

Status

Accepted

Amends ADR-0003: Use NATS as distributed message bus

Context

NATS messages are, at their core, just byte arrays that need to be re-interpreted if needed. It is therefore up to Telestion to decide if we want to have additional recommendations and/or requirements for messages sent via the message bus in Telestion applications.

Based on the experience from the RocketSound and Daedalus 2 projects, there are two prominent most needed types of data processed in a Telestion application:

The NATS documentation explicitly mentions JSON as an example for structured data and includes JSON support in many of its libraries (including, but not limited to, for TypeScript).

Microservices are the most modular / work the best when they don’t need to know about origin or destination of their messages (as such a requirement would “distract” from the single responsibility pattern).

Decision

We will use (and recommend the usage of) a UTF-8 encoded JSON string as payload format for structured data.

We will consider any message (including structured data) to have an unknown type until it is explicitly validated by the service receiving the message. We will not assume the existence of any properties / the type of any JSON-based message until it’s fully validated (for example, in TypeScript, through the usage of a library like zod).

We will use (and recommend the usage of) the raw binary data (without any additional encoding) as Int8Array for binary / non-structured data.

We will allow the usage of headers only as additional metadata (for example, the time that the message was received), but consider the existence of headers to be optional (any services must be able to process any message that they could process with headers just as well without headers). We will include any information that affects the control flow of messages in either the hierarchical subject or the payload, but not the headers.

Consequences

Headers example

If Service 2 can handle this,

flowchart LR

s1[Service 1]
s2[Service 2]
s1 -- "data + headers" --> s2

is can also handle this (and thus requires no knowledge of the data’s origin):

flowchart LR

s1[Service 1]
m[Middleware Service]
s2[Service 2]
s1 -- "data + headers" --> m
m -- "preprocessed data" --> s2