Okay,
I’m trying to figure out a good way to handle pub/sub logic when using GES.
In Johnathan Oliver’s Event Store – now NEventStore (NES), I think I understand the general principles (but correct me if I’m wrong):
-
Natural concurrency checks do not require DTC transactions if only one aggregate is modified per unit of work (equivalent to writes to one stream per unit-of-work in GES)
-
The order of events written for a specific Aggregate will be preserved (in GES this is guaranteed ordering per-stream)
-
A good way to build read models is to use subscriptions (works about the same in both GES and NES) – you get ordering guarantees per aggregate/stream this way
-
It’s fine to persist the same event into several streams (e.g. a single event changes the state of an aggregate, and can also be used to change the state of some kind of process-manager/saga thing, if that “thing” is also event-sourced)
-
With NES, the idea is that your events to dispatch on your bus (and possibly also commands for a JO-Saga) are persisted as part of the “commit” and are guaranteed to be dispatched to the (external) Bus as part of the commit process.
I’m trying to figure out how to handle #5 w/ GES – essentially coordinating work between streams.
My understanding of the general way to handle this is to modify a single stream during each unit of work, then issuing-a-command/publishing-an-event and having another handler that does the some work with another stream.
With GES, handling events seems to make sense, you’d do it the same way you’d build your Read Model – use a subscription (probably using competing consumers so we are getting exactly-once delivery) and then figure out what logic needs to handle the event.
For commands, would it make sense to take the same approach? For example, simply write commands into the same GES stream (or create some kind of pseudo event “CommandDispatched(cmd)”) and use a competing-consumer-subscription to execute the commands? Only JO-Saga style entities would be dispatching commands.
I can think of a couple ways of handling this:
a) Use my Bus for handling dispatching commands/events and write events to GES to persistence, using DTC to tie the two together (probably a bad idea)
b) Totally ditch the Bus, and use GES – but now there’s issues dealing with SLAs, retries, error queues, poison messages, etc. I suppose I could use a few different streams to handle this logic, but I think I end up writing my own Bus at this point…
c) Write everything to GES, then have a subscriber that takes all events and “DispatchedCommands” and sends them directly to the Bus. It’s only responsibility is getting these messages to the Bus infrastructure.
Does anybody have any thoughts/experience/guidance on how they’ve handled this sort of situation?
Am I even heading down the right track here?
Thanks.