-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resolve the issue of the handleEvent being called twice after handleCommand is called in Actions. #60
Comments
Events should be persisted once command is validated (constraints are checked). Or am I missing something? |
This has tripped me up in the past and I've been meaning to open an issue too. Thanks for remembering for me ;) |
@pawelkaczor you are right about the order of persisting. We produce Events by applying a command on the current aggregate instance. But before we really persisted the events, we must be sure that we can apply the events on the aggregate. Imagine the situation where we add a command handler that produces one event, but we don't add an event handler for it. In such a scenario, we end up with an event on the storage that can NOT be handled. That's why I was first applying the events to make sure we have event handlers for it. In case it's missing, the command is rejected. Of course, this is not bulletproof (or foolproof). People can always remove event handlers for events that are already persisted. In which case re-playing events won't work anymore. |
I'd argue that the library shouldn't care if there's an event handler or not (although I do like the warnings). If the command is valid, it should raise an event, that event should be persisted, and after that, there should be an attempt to apply the raised event. The most important part of this is persisting the event. That's what our aggregates are for after all. |
@rcavalcanti so, if I understand correctly, the fun-cqrs performs some kind of sanity-check of the Aggregate Root implementation on the runtime, that can result in command rejection Unfortunately, the sanity-check algorithm may be confusing (the issue #60 has been created) and probably introduces accidental complexity. I would suggest reconsidering its value. I think this kind of quality assurance should not be implemented in the main code, but rather in the tests. |
Fair enough. Thanks for the valuable feedback. |
Hi all, There is a fix for this on branch feature/issue_60. I solved it in a slight different way. Event handlers are only called once, but the sanity check is still in place. I keep it because I realised that I had already to paths doing an explicit sanity check and another one that was doing it anyway (let's say by design). I explain... The Interpreter has three methods: def onCommand(state: State[Aggregate], cmd: Command): F[Events]
def onEvent(state: State[Aggregate], evt: Event): State[Aggregate]
def applyCommand(state: State[Aggregate], cmd: Command): F[(Events, State[A])] The The Akka backend was not using the The updated aggregate was produced only after the confirmation that all events were persisted. The InMemoryBackend was already using the So, the fix consist in promoting the usage of I'm not merging it yet, because I would like to have some more time to revise the code. Feel to do a code review as well if you are in the mood. Is much appreciated. ;-) |
@rcavalcanti nice to see the improvement 👍 But, I think your explanation of the fix does not reflect actual changes in the code - I saw that the implementation of the |
Euh! The main change in Now, whoever implements a backend has call |
@pawelkaczor the error in The only clean way of doing it requires: |
@rcavalcanti Thanks for the explanation. |
In reference to the issue with when handling a command the handle event code gets called twice.
The following details why it occurs:
This happens because after applying a command we apply all the events to the aggregate before sending it to persist but we discard the aggregate state after persisting, we re-apply them without discarding this is done to ensure that no event is persisted if they can’t be handle later
however, we could do it in a more intelligent way we could apply it only once and keep two versions of the aggregate: before and after if we succeed in persisting the events on the store, we drop the old version, we keep the updated one and make the aggregate available to receive the next command.
The text was updated successfully, but these errors were encountered: