So, we’re about to begin this journey. Before discussing how to implement a notification server, I should probably explain first what we are trying to build. That is what is a notification server?

Everyone has their own viewpoint on this, and here I will describe my own. A notification server is a box which consists of components which are linked to each other. It could be thought of as an engine, where each component is thought as a gear in the engine’s gearbox. A component may be linked to other components, and it may be not linked to any component at all. The link is directed, so if one component is linked to another, then the other component is usually not linked to the first one. We say that component A is linked to component B if there is a directed link beginning at A which ends at B. We say that component A is a component linking to component B in this case. In terms of math models, we just described a structure of a directed graph, where our nodes are called components. Our graphs actually allow multiple edges between nodes (a directed multigraph), but we will get back to this in a later post, and you can forget about the multiple edges for now.

A component should be thought of as a single processor unit. Components should do a single thing and do it well. Data flows between the components of the server based on the components’ links. The data is referred to as an event. We refer to the structure of components links as the pipeline or the graph of the server. We can divide components into three types, based on their link support:

  • Source components are components that can not have any components linking to them. These components are expected to produce events which will be consumed by the components linked after them.
  • Target components are components that can not have any components linked to them. These components are expected to consume events and not to produce any further events.
  • Transform components are components that can have both components linking to them and linked to them. These components are expected to consume events and to produce other events.

I should mention that a component of certain type may appear multiple times in a server (i.e., multiple instances of the component appear in the server), and therefore we can not tell the type of a component just by looking at the graph of the server.

It is customary to divide components into three categories, although not all components fall under these categories:

  • Listeners: a listener is a component that listens to some external source and produces events for the components linked to it. A listener is a source component. An example for a listener could be a component that checks whether a file system directory has changed and produces events according to that. The events produced by the listener in the example may vary according to implementation: they may contain the name of the file that was changed in the directory, or they may contain no data, but just indicate that the directory has changed.
  • Dispatchers: a dispatcher is a component that receives events from a component linking to it and publishes these events to an external target. A dispatcher is a target component. An example for a dispatcher could be a component that receives events and creates corresponding files in a file system directory.
  • Logics: a logic is a component that receives an event from a component linking to it, maps it to a different event using a transform function, and produces the mapped event to the components linked to it. A logic is a transform component. An example for a logic that receives events from the file system directory listener above, is a component that creates a new event consisting of the name of the file that was changed and its file size.

An example for a component that doesn’t really fit into any of the above three categories is the timer component, which publishes an event every certain amount of time. The timer is a source component.

The notification server is a framework that allows one to write these sorts of components, host them in a server, and run the server. It allows components to run asynchronously, that means that components can run in parallel, without interfering with each other. The concept of what described above is known and is referred to as Dataflow programming or Flow-based programming, and there are many implementations known, such as TPL Dataflow. We will explore the current implementation of the notification server and try to compare it with other existing solutions.