6. StateDrivenEntity
Contents
Today we are going to talk about one of the most infamous mechanisms of the notification server: StateDrivenEntity
.
Recall that every notification server can be thought of a gearbox, consisting of components which can be thought as the drive wheels. When our application launches, our notification server is at first not running. We need to perform some action in order to make it start, similarly to how we need to insert an ignition key and turn it in order to start a car engine.
The mechanism that supports this in the notification server framework is called StateDrivenEntity
. It allows a class to declare a current state. The entity also provides an api that allows users to change its state:
|
|
The type State
is an enum:
|
|
The possible states have the following meaning:
- Uninitialized - the entity was created but was not initialized yet. This means that some of the entity’s members are not initialized yet.
- Initialized - the entity was created, all its members are initialized, but they aren’t started yet. For instance, suppose that our entity is a component that uses an HTTP listener to receive requests. When this component’s state is Initialized, its HTTP listener data member would be initiated, but the component would still not be receiving HTTP requests. This means that a method of the sort
Open
orStart
of the HTTP listener was not called yet. - Started - the entity was created, all its members are initialized and started. Continuing with the previous example, if the previous component’s state is Started, it means it is receiving HTTP requests. This means that a method of the sort
Open
orStart
of the HTTP listener was called. - Invalid - the entity is an invalid state. This usually means that an unhandled exception was thrown when the entity was in one of the previous states.
There is some hierarchy among the states described above: an entity begins with state Uninitialized. We can then transform it to any state. However, if we transform it to Started, it will first transform to Initialized and then to Started. Similarly, if an entity is in state Started, we can transform it to any state, but if we transform it to Uninitialized, it will first transform to Initialized, and only then to Uninitialized. If an entity is in state Invalid, transforming it to any other state will be equivalent to first transforming it to Unintialized and then transforming it to the requested state.
There exists an abstract class that users can inherit from in order to implement the IStateDrivenEntity
interface:
|
|
Users can inherit from this class and implement the methods to specify the behavior of their entity when it transforms states. There is also a class called StateDrivenEntityHelper
which provides an implementation of StateDrivenEntity
given delegates for each of these methods:
|
|
In the notification server framework, every component class implements IStateDrivenEntity
, with the help of StateDrivenEntityHelper
. Each component class contains virtual methods with the same signatures as in the definition of StateDrivenEntity
. For example, here is how an implementation of the state transform methods of a HttpListener
class:
|
|
We remark that in InnerStartedToInitialized
we recreate the HttpListener
. In principle, we could just call Stop
, but there is a problem due to an implementation detail: HttpListener
does not allow calling Start
after we called Stop
.
The last thing I want to explain is why I said this mechanism is infamous. The problem here is that C# already defines standard points for initializing your class and for cleaning your class resources: these are the constructor and the IDisposable.Dispose
method, respectively. The concept of IStateDrivenEntity
kind of conflicts with these, as your class instance is not in a valid state until you call TransformTo
with the appropriate state. We are currently still reviewing the current design/implementation of the notification server, and IStateDrivenEntity
is one of the main concepts there. Think how you would design this differently: this is not an easy problem.
Author זלינגר
LastMod 2020-09-26