Observability X – Subscribers

The Sources interface in the Substrates API allows for a number of ways to set up a Subscriber and in turn an outlet Pipe. Subscribers provide the means to connect one or more Pipes with emitting Subjects within a Source. When a Percept (instrument) emits a value, that value is forwarded to all Pipes that have been connected by a Subscriber via a Registrar.

The Source interface has two groups of subscribe methods. With the first group you provide a Subscriber, which will be notified when a new Subject begins emitting data. In the callback to the Subscriber it provides access to the Registrar for the Subject, enabling the registration of one or more Pipes. The second group is where the same Function or Conduit is used to process every emittance from a Subject within the Source. The choice of which group to look at one comes down to how much control is needed over the selective registration of a Pipe with a Subject.

An example will help here. Consider the scenario where you have a namespace of Pipes and you want to relay an emitted value to each prefix, in terms of namespaces, of a Pipe. To do this, a function can be passed to the subscribe method that accepts a Subject parameter and returns a Pipe; here the Pipe is a function that consumes an emission (value). Note we aren’t taking the enclosure of the Subject but of the Name assigned to the Subject.

In the code below, the enclosure method is executed for every single emitted value from a Subject. This method takes a function that consumes the prefix by using it to look up the pipe in the conduit and passing on the emitted value. This is like when a record is dispatched to a Logger and dispatched onto a parent of a logger. The difference here is that this is done by way of Subscribers who consume values emitted into a Pipe and then forward it onto a parented Pipe.

With the above function subscribed to the Source, the following will result in five emissions as opposed to one.

However, there’s a more efficient way to achieve this using a Subscriber that registers a Pipe for each prefix only once. The following code essentially connects the output of one Pipe directly to another Pipe. The Pipe we register to consume the value from is the prefix of the Pipe itself. This is crucial when modeling and managing hierarchical flow systems.

Of course, we could have made the caller of the initial emit do the traversal from child to parent as follows:

Beyond the ugliness of having a client code change because we want to implement a multi-dispatch like operation, we also incur costs when we cross thread boundaries for each call to emit on a Pipe. In contrast, with the Subscribers above, we only incur this cost for each leaf level emittance as all other processing is done within the Circuit’s thread.

How fast is the efficient Subscriber implementation above? On a Mac mini (Apple M4) it has a wall clock cost of 29 ns per each leaf emit call, which is 6 ns per Pipe emit (5 name parts).