Let’s look at the solution build log: there’s a warning:
If you follow the link in the warning you can read a very detailed description of the issues of using sync and async NeventStore event dispatcher. In summary, there could be a problem in the order in which events (in very rapid sequence) are dispatched.
To overcome this issue, Damian Hickey suggests:
The only way to guarantee the order is to read from the store separately
To do that, in the next version 6 of NEventStore, we will be able to use an improved EventStoreClient; in the meanwhile another solution could be used: PollingClient.
With this solution there is a real separation between command stack and query stack(s), because the read model is setup as a client for consuming events for its own purposes; this means that the read model stores the checkpoint of the last event consumed and periodically check the Event store for new events. When this occurs the PollingClient starts a process to consume the new events and store the checkpoint number of the new last event consumed. each projections should be set-up as a polling client that reads and consumes the events.
Ok, how to do that?
That has been explained by Damian Hickey in the comments of the same issue. Here it is:
In the same answers Lars Wilhelmsen shows a pretty complete and absolutely understandable example about the concept expressed by Damian, so to sum up:
- the event dispatchers are obsolete and will be removed in future versions
- The alternative is to use the polling clients (usually to implement as services on the stack of the projections they populate). NEventStore comes with its own PollingClient that already brings within it all the logic of forced and regular activation typical of a poller
- The PollingClient returns a stream of commits to process and passes it to an IObserveCommits (code) which can subscribe any specific Observer, which will process the commit stream with its own logic (code). From this point of view, NEventStore proves flexibility. It allows both to have one PollingClient and several Observers that can populate different projections, or, in more complex scenarios, more PollingClient that do the same thing, but each with their own frequencies, and with its own specific set of Observers.
- In some scenario or for some projection it is important to have, when possible, a real-time (or “near-real time”) update when an event occurs in the life of the application. That could be achieved by defining a specific PipelineHook that is listening to the flow of commits on NEventStore and activates a polling cycle every time the commit it has been correctly processed by NEventStore. The devil is in the details: note that if you use a DI container, you can encounter some annoying CircularDependencyException. If you refer to the published code, the exception I came across had this very clear message:
The problem is that StoreEvents has to know the PipelineHooks, which starts a cycle of polling of the PollingClient, which in turn depends on the StoreEvents, creating the most classic circular dependency. From my point of view, however, the design is correct, but we must to tell Castle.Windsor not immediately resolve the dependencies of the IObserveCommits when resolve the IStoreEvents, but to wait for the time of the actual use. To do this, I followed these steps (but it’s not the only way):
- Enable Castle.Windsor to resolve the dependencies in a lazy way
- Define the dependencies of the PipelineHook as Lazy
In my opinion
The NEventStore guys did an amazing work, but, as they have already anticipated, there’s something to do about the PollingClient. What I dislike is the way which has been thought to work with checkpoint number. In my implementation I haven’t figured how to do better: so the checkpoint number is loaded and used by the PollingClient, but it’s updated outside of it and, with the possibility to subscribe multiple IObserver it’s important to define which of the observer will update the last checkpoint number (at the end of all the PollingClients cycle). I’d like to have some checkpoint-number orchestration wrapping the PollingClient or something like that.
Anyway, Damian has already announced some news about this topic, so…I’m waiting for NEventStore version 6