Closed ch3pjw closed 7 years ago
This isn't something that eventful
has the goal of supporting natively. There are way too many variations on how to handle a side-effect to be able to properly create a general system for this. This is part of the general advice of "avoid CQRS frameworks" since evreyone's use cases are too different. The goal is for eventful
to provide useful, composable building blocks for CQRS/ES systems, not to be a framework.
If you have some HTTP service that handles when a user clicks the "Submit Email" link, then you could send the email in that service. For example:
EmailSubmitted
event in the event storeNote that there are a lot of variations on this. For example:
EmailSubmitted
before sending the verification email, so if the verification email sending fails and your power gets shut off, you can restart your service and check for any EmailSubmitted
states that haven't been "completed" with an VerificationEmailSent
event.EmailSubmitted
events and that sends the verification email when it sees them.Let me know if this helps at all! I hope this explains why something like this isn't built into eventful. Feel free to ask any more questions you have about this situation in particular.
Yes, it's really helpful to understand why there wasn't an obvious place to put this stuff. I ended up going with your third suggestion where I have something that's responding updates, working out if it needs to send emails and then saving an EmailSent Type
event in the store. I didn't go with the ReadModel
abstraction yet, as I don't think I've quite got my head around it. I've made the thread that's emailing read off a queue that tells it a particular UUID has been updated, then it goes and reads the latest projection for that UUID and acts appropriately. Doing that felt better than polling.
So, I guess my follow on questions would be:
ReadModels
/how do I use them correctly?ProcessHandler
was for side-effect free coordination of state change across event streams?Many thanks!
I'm considering scrapping the ReadModel
and ProcessManager
classes. I created them while working on the bank
example, and they work fine. However, they aren't really general enough to deserve those names, and now I see how misleading it can be. Maybe I will rename them or get rid of them.
What's the intended purpose of ReadModels/how do I use them correctly?
I made them while making the examples. I think I'm going to rename them to SimpleReadModel
or maybe scrap them. If I can make them more general I'll do that. For now I wouldn't use them as they will change.
Was I correct in thinking that ProcessHandler was for side-effect free coordination of state change across event streams?
Correct. A ProcessManager
is a Projection
that has functions to get any pending events or commands it wants fired. Again, this isn't the only way to do process managers, so I might rename it SimpleProcessManager
or ProjectionProcessManager
, or get rid of it and replace with some documentation on how you might build one.
Is triggering an update via a queue a reasonable solution, or is there a better way to get notified in an event-driven way about store updates?
You can use a GlobalEvenStoreReader
instead of having a separate queue. This way your thread can poll the event store for any events on any stream. If it sees an EmailSubmitted
event, it can send that verification email.
I've heard/read of a great system that I use personally. Instead of always being push based (queue) or pull based (polling) for your events, you can use a combo. By default, poll at some specific interval, like 1 second. However, build into your polling thread some "wakeup" that allows it to skip the rest of its wait period and poll immediately. In your case, your thread that polls for email submitted events can by default just poll every second, but you can use your queue to wake it up when an event of interest is stored. All you have to do is store the last processed SequenceNumber
so you know where you left off last.
The advantage of this sleeping polling system is:
I'm thinking of using this in production - is that a good idea?
I would hold off on that 😄 I personally use this in production for a couple systems, but I'm also the author and I currently just change parts of eventful
if I find deficiencies. Once I have way more documentation (including docs on how to do things that aren't built into eventful
, like in this case), and I've settled in on most of the APIs, I'll make a release announcement in the usual places.
I'm also hoping to flesh out the bank
example as much as possible so I can refer to it for common use cases in the docs.
Cool - I like the idea of mashing together the polling/wake-up flow. As you say, it means you only have one way of getting data.
The thing I'm working on is quite small, so I'm not too worried about changing APIs too much. I rather want to see how event-sourcing plays out in the wild for me. I'm trying out Haskell in production for the first time too :grin: I'll let you know how it goes, and I'm really grateful for your detailed responses so far.
As far as the ReadModel/ProcessHandler examples go, I definitely found they took me quite a long way from what you are describing here as the intent. I think, perhaps, if they had been in examples/
rather than eventful-core/
and eventful-memory/
I'd have given them less weight. The names probably would hint at me that I'd want to model my own things on them, but I think I'd rather have just worked out that bit on my own than try to emulate. (That is, a clearer distinction between what eventful
does and does not address would have been more helpful to me.)
Great, thanks for the feedback and good luck! 😄
I've been reading through the code for this library, including the examples. Perhaps I'm missing something, but I'm struggling to find an example of where to put side effects that I might want to execute when a command has been issued in a particular state or has caused a particular state to be reached.
I've tried reading the code, but I'm not sure I quite understand CQRS enough to understand the command-centric layers of
eventful
fully.As a concrete example: if I want to model an email sign-up scenario, I presume I would have states like
HasNotRegistered
,HasClickedSubmit
andHasClickedVerify
. I would haveSubmitEmail
andClickVerify
commands that would move through the states. However, on handling theSubmitEmail
command, I not only need to emit anEmailSubmitted
event to update the state to contain the submitted email address, but send the verification link via email so the user can click it to submit the next command.As far as I can see, the existing
CommandHandler
used in the "counter" example doesn't permit side effects in the type, and nor doesapplyCommandHandler
. I looked atProcessHandler
, but the intent of that just seems to be coordinating state changes across multiple streams. I wondered whether aReadModel
was the right way to go, but it felt like polling in the example wasn't nice, especially in something that's very event-driven to begin with. What am I missing?Happy to contribute a working example to help others figure this out if there's an obvious answer I'm missing.