Closed dharmaturtle closed 2 years ago
Hm, a good question!
The intent in the docs is to call out specific families of 'projectors' and 'services' in a system in order to allow a higher level vocabulary to be applied. In that context, an Ingester is a specific kind of reactor whose primary job is to take in data and stash it in a suitable way for this overall bounded context.
Where an ingester writes into an event sourced aggregate (but, even if you run a CFP with RollingState - you'll still see each change guarantee a handler invocation), it actually is doing more than the strict act of 'take it and stash it'.
The name of the file Ingester.fs in the reactor template results from a combination of:
b) being copied from summaryConsumer
(that template is definitely an Ingester overall)
a) from the fact that proReactor is about 6 templates in one (which is why program.fs is a nightmare of ifdef
s) - there is already a Handler.fs which is used for the 'real reactors' and for some that are more like publishers.
My attempt to define ingesters vs publishers vs reactors happened after this... After https://github.com/jet/dotnet-templates/pull/91 is merged, it might be a good idea to rename Ingester.fs
in all the contexts to just be Handler.fs where possible (but that's still hard in proReactor).
The events are then treated as Commands, which breaks my brain.
That's what a reactor should be doing by definition. However when ingesting/denormalizing things from an event source, you generally want to do that processing idempotently in order to ensure that rewinding the offsets on the source does not e.g. destroy or add conflicting information - e.g. if your read model has a projection from V5 of a stream, and e.g. the projector is restarted before it can save its offsets and/or you reset them and/or you are working from a source that can present events multiple times (hint: that's really all sources - At Least Once Delivery is a reality for most things and thats what Propulsion centers on and most logic in most Handlers should be considering that).
Regarding your actual need, proProjector
should cover your need in this instance, but proReactor -blank
would work fine too. To be honest, if I had time and was focusing on the understandability of the templates, my next tasks would be:
I'd take and/or be happy to work with you on a PR that kicks off that journey by e.g. taking proProjector
, taking out lots of stuff (esp Kafka - proProjector and pushing to kafka was the first use case but in the greater scheme of things it really should not be that central). I guess that would be a proDenormalizer
/proReadmodelUpdater
or hopefully a better name !
I think this is the best place for us to have this discussion but feel free to reach out on the DDD-CQRS-ES slack's equinox channel too...
@dharmaturtle we never really put this to bed properly
Since the above, thanks to @ragiano215's initiative (and the nudge you provided by asking the question and getting me to put out my thoughts above) we have a proReactorCosmos
template which is much more legible.
It calls the file with the handler within it Reactor.fs
and the Reaction event filtering has a specific section and patterns now: https://github.com/jet/dotnet-templates/blob/master/propulsion-cosmos-reactor/Todo.fs#L23-L31
I have intentions to add a Reactor to https://github.com/oskardudycz/EventSourcing.NetCore/pull/84 which will expose a Feed Source based on the pattern in https://github.com/jet/dotnet-templates/tree/master/equinox-patterns#list-epochsseries-with-exactly-once-ingestion-guarantee
At this point I'm going to close this issue; feel free to ask any follow-ups and/or call me out on stuff that's unclear/dubious
Link to file in question.
I ask because the Propulsion docs state
It further states:
My reading of
ReactorTemplate.Ingester.handle
is that it is acting in reaction to events from the event store. In particular, it is passing events toTryIngest
, which apparently tries to Consume the event. Am I correct in thinking thatIngester
is a Reactor, or are there nuances/grey areas here that I'm missing? Things might be complicated because it is producing its own event stream for reasons I currently don't grok. (The events are then treated as Commands, which breaks my brain.) I might be being too pedantic and you mean this as a more throwaway example.Ultimately, I'm trying to figure out what to base my (non Kafka) projector code on. The proReactor template looks promising, and instead of a
TodoSummary
module I'll have aTodoProjector
which writes to Azure Table Storage/ElasticSearch in response to events.