Skip to content
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

rollback aggregate to a given revision #154

Open
stefanomiccoli opened this issue Jun 24, 2020 · 5 comments
Open

rollback aggregate to a given revision #154

stefanomiccoli opened this issue Jun 24, 2020 · 5 comments

Comments

@stefanomiccoli
Copy link

Hi Adriano,

kudos for such a great project.

I honestly can't tell at the moment if my issues are dependant on the lack of knowledge (most likely) of cqrs and event sourcing, my misunderstanding of the docs, or just the wrong use case.

We are using cqrs-domain to store any changes to articles in our platform, pretty much as described in this stackoverflow issue.
So far it helped to keep track of who changed what and when, but we are now about to enrich our webapp by providing the history of changes.

The first step will be to get the list of changes, i.e. all the events generated for a given aggregate id. And here comes the first issue. Looking at the docs and code of cqrs-domain i couldn't find any method to get such list. Merging snippets from this and eventstore projects, the neatest solution I found was to get the eventstore from the domain and then get the events, with something like domain.eventStore.getEvents('streamId', skip, limit, (err, evts) => { /* my business logic */ }). It works just fine, but im not sure that bringing into our code details of eventstore implementation would be ideal. Anywat, is this the correct way to go? any better way im missing?

Then, the big issue... How to restore a prev revision. Before reading that stackoverflow issue, i thought of something very close to the depicted state comparison. Ideally, the way I would achieve this is:

  1. trigger command restoreRevision with the expected streamRevision in payload
  2. load aggregate at the expected revision
  3. compare the aggregate at the target revision with the aggregate at latest revision, make diff and store it as payload of the revisionRestored event
  4. return the aggregate

What I'm missing in step 2 is a method of cqrs-domain to ask for an aggregate at a given point in time (revision). In this case it seems not enough to just load the events with domain.eventStore.getEvents because I would be missing all the logic of the events defined in the domain (i.e. how the event payload has to be merged in the aggregate).

Full of despair, i was looking at the code of the defaultCommandHandler searching for a way how to get all the events and eventually override the commandHandler for a custom one, but then got a hint from the docs that I'm probably looking at the problem from the wrong standpoint

More specifically, this step in the docs sounds a bit obscure. In which way sagas and microservices would overcome the need for a custom command handling?

IMPORTANT HINT:
Is your use case not solvable without a custom command handling? Sagas? Micro-Services?
@stefanomiccoli stefanomiccoli changed the title Suggestion on rollback rollback aggregate to a given revision Jun 24, 2020
@adrai
Copy link
Contributor

adrai commented Jun 24, 2020

Sorry for not answering in a more complete way... have not that much time right now...

The first question I had when reading quickly what you described: Aren’t you denormalizing the events? i.e. with cqrs-eventdenormalizer?

A basic example here: https://github.com/adrai/cqrs-sample

Sorry, again.

@stefanomiccoli
Copy link
Author

stefanomiccoli commented Jun 25, 2020

ah, no we are not using cqrs-eventdenormalizer.
Indeed, since our frontend was not able to handle async notifications (e.g. websockets as in your cqrs-sample) we did a nasty workaround, by hooking to the command callback of the domain.handle() call, manually generate our pseudo-viewmodel form the returned aggregate, store it in our read db (just another mongo collection) and return it in the response for the PATCH http request. I still feel a bit guilty when I think about this, but just say it was recorded as technical debt.

Now, thanks for the hint and I will dig into the docs of cqrs-eventdenormalizer and scratch my head how it could fit in our current setup. Of course any further help when time allows it would be more than welcome!

@adrai
Copy link
Contributor

adrai commented Jun 25, 2020

you don’t need any websocket or handling of events in the client...
Just fetch the denormalized data, like here: https://github.com/adrai/cqrs-sample/blob/master/host/app/routes.js

@stefanomiccoli
Copy link
Author

Of course, no need for that when handling queries (basically GET requests).

But when it comes to commands (PUT, PATCH, DELETE) I can see only 2 possibilities given the current limitation of our UI/UX which involves providing feedback to the user in the form of the updated resource:

  • synchronous, the response of http requests for commands containing the updated info (current workaround)
  • asynchronous, domain handle commands and emit events, denormalizer handle event and emit notifications, but in this case, in order to send the info to the frontend a websocket or polling needs to be in place, no?

fetcing the denormalized data in the callback of domain.handle would not ensure (and most likely not work) the updated data cos i have no clue when such async task will end

correct?

@adrai
Copy link
Contributor

adrai commented Jun 25, 2020

It depends... but if you want to go full sync... you could:
create a POST request (or similar) containing the command, in the route handle, pass the command to the domain (via bus or whatever), you could also use evented-command to wait for the event to emit: https://github.com/adrai/node-evented-command#send-commands and finally respond to the POST request with the received event in the payload.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants