Reading up on CQRS there is a lot of talk of email notification - i'm wondering where to get the data from. Imagine a senario where one user invites other users to an event. To inform a user that he has been invited to an event, he is sent an email.
The concrete steps might go like this:
A CreateEvent command with an associated collection of users to invite, is received by the server.
A new Meeting aggregate is created and a method InviteUser is called for each user that is to be invited.
Each time a user is invited to an event, a domain event UserWasInvitedToEvent is raised.
An email notification sender picks up the domain event and sends out the notification email.
Now my question is this: Where do I go for information to include in the email?
Say I want to include a description of the event as well as the user's name. Since this is CQRS I can't get it thru my domain model; All the properties of the domain objects are private! Should I then query the read side? Or maybe move email notification to a different service entirely?
In CQRS, you're separating the command from the query side. You will always want to go to the query side in order to get data for a given event handler. The write database is going to be a separate database that contains the data necessary for building up your domain objects and will not be optimized for reads, but for writes.
The domain should register and send an EventCreated event to the event handlers / processors. This could be raised from the constructor of the Meeting aggregate.
The event processing component would pick up the EventCreated event, and update the query database with the data contained in the event (ie, the Id of the event and its name).
The domain could register and send a UserWasInvitedToEvent event to the event processors.
The event processors would pick up the UserWasInvitedToEvent and update the query store with any reporting data necessary.
Another event processing component would also pick up the UserWasInvitedToEvent event. This process could have access to the query database and pull back all of the data necessary for sending the email.
The query database is nothing more than a reporting database, so you could even have a specific table that stores all of the data required for the email in one place.
In order to orchestrate several different events into a single handler (assuming the events might be processed in a different order at different times), you could utilize the concept of a Saga in your messaging bus. NServiceBus is an example of a messaging bus that supports Saga's. See this StackOverflow question as well: NServiceBus Delayed Message Processing.
Related
I was developing the chat app in flutter using firestore, the users successfully chat one-to-one. but I also want to send the notification to the user that someone sends him/her a message. For that I decided to use the cloud messaging service of firebase, but how can I check that the user read the message or not.
There is nothing built into Cloud Firestore to track which user has read a specific document already.
The two most common approaches that I know of are:
To track for each individual message and each individual user whether they have read it, so by keeping a list of the user IDs in each message document. While this potentially stores a lot of extra data, it is the most direct mapping of your use-case.
In most chat apps though, tracking of what messages each user has read is done as an "up to here". So if the user has read all messages up until a certain one or a certain time, the assumption is that they've also read all the messages before that one/moment.
For this model you can instead just keep a single document ID or timestamp for each user (i.e. readUpTo), instead of having to mark each message for each user that has read it. In your UI, you then determine whether to show each message as unread based on the message ID/timestamp compared to the timestamp of readUpTo.
I am building a web app that users can edit and share notes. Users should be connected to notes with roles (owner, read, read-write). This is an occasionally connected system so I chose to do the syncing using CQRS and event sourcing. Following Greg Young's presentation [36:20 - 38:40], the flow would be as follows:
Client does changes while offline.
Client connects to the Internet.
The "store and forward" sends the events that occurred while the client was offline.
Client compares the local events with the received events and does a merge, deciding what commands to keep. Then updates local view model.
Client sends the stored commands (created offline) to the server.
Server executes the commands and generates events that are stored in event store.
"store and forward" holds the events each user is interested in, until the users come back online.
The question is: How does the "store and foreword" decide what events should be sent to each user?
Obviously sending all events would compromise the security of other users.
Since your client knows which aggregates it displays, then it can just tell backend "hey, are there events for aggregateIds [...] since [timestamp]?".
This is how reSolve framework keeps UI reactive - client subscribes to events for particular aggregateId and receives them in real time via websockets.
So one answer to your question could be "let user ask for events (aggregateIds) he is interested in"
I am trying to implement queues into our microservice architecture, to be specific AWS SNS/SQS.
For example I have this scenarion.
After order is created Orders MS raises OrderCreated event and this event publishes message to AWS OrderCreated SNS. SQS queue InvoiceCreate is subscribed to OrderCreated SNS and will get this message.
Evertyhing makes scence so far. If Invoicing MS is listening to InvoiceCreate queueu and retrieves all new messages - Invoicing MS should create an invoice, but my question is with what data?
a) contact Order MS (to order data relevant for creating invoice). If unable to do so, message will be left in queue until Invoicing MS is able to collect the relevant data
b) message published should contain all the relevant data needed to create an invoice.
If choosing A Invoicing MS will not be decoupled and it will be depending on Order MS, but on the other hand it can collect additional data other then the data packed with original message.
If choosing B, since OrderCreated event and OrderCreated SNS doesnt really know who will use message data ie. OrderCreated could be also used to perform different actions, I am confused how to preciselly decide what data should be stuffed in this message
Our architecture is set up more like your option B. To use your example, the Order service would publish it's OrderCreated event and attach - as a payload - most (or even all) of the Order information in the Payload section of the message. We format message and payload as JSON for compatibility, but you can do whatever.
In some cases, we don't publish all info, just specific fields for the Added/Edited entity - it depends on the service and the sensitivity of the information. So long as you only ever add fields to a message (don't remove any), you are honoring the contract and aren't really tightly coupled to it.
Again, to your example, the InvoiceService could get its information from one or more of several options:
Pull it directly from the OrderCreated message if you include everything needed
Pull what it can from the OrderCreated message, publish an InvoiceStarted event that triggers the OrderService (and/or others) to send it an OrderInvoiceComplete message with the rest of the details it needs
Keep a local copy of whatever key data it needs - populated by subscribing to other events - so that it can combine OrderCreated data with some local data to flesh out an invoice
It's best to avoid the InvoiceService responding to a message by making a call directly back to the OrderService - this is a pretty tight coupling that can be avoided by simply messaging back if you have to.
So, there are lots of options. I personally prefer the technique of putting all data that might be useful into the messages when things are created/updated and letting consuming services decide what to use/ignore. For our scenario, that works well but we have only a few well-contained clients accessing our services so there may be more secure ways to do it that aren't relevant for us.
I'm trying to model a simple event application.
Basically:
A User can create an Event
A User can invite many Users to an Event
A User can accept/decline an Invitation
A User can retrieve an Event if he's the owner or is participating (accepted Invitation). The difference should somehow be visible in the returned objects
A User can retrieve Event's current accepted/declined Invitations (actually Users, not foreign keys)
A User can remove himself from an Event
To many things to think about so it's all mixed up in my head and I'm losing the whole picture. I don't fully understand how I should implement accept/decline Invitation and how I should retrieve information about current participants. What are the relations behind?
I think I know how to do it with references only, but my front-end is mobile so I don't want to make a lot of requests to get every object by reference after the first fetch...
If someone could lighten me up...
Thanks :)
You should have an invitation model and an event model with the following fields.
Invitation : eventId, userInvited, accepted
An invitation belongs to an event and belongs to a user
Event : your event details, event owner
Then for a user you can do a remote method that gets the events with
Invitation.find({where: {userInvited: user.id}}, include: 'event')
.then((event) => event.id)
And with the event, gets all the users
.then((eventId) => Invitation.find({where: {eventId}}, include: 'user'))
.then((invitations) => invitations.map((invitation) => invitation.toJSON().user))
It's a quick draft of how to achieve what you want.
In a webapp (ASP MVC), I have a view/page that lists new notifications/incoming messages similar to a list box (picture a mail box, but much simpler) across sessions for users. I understand INotifyPropertyChange and Observables
My scenario: I have a simple Transactions table with a TransactionType, only some transactions with Transaction.Transactype == Approve/Reject need notifications.
How do I model this in the database and the object so that I can pick up these changes, everytime the user logs back in, across session?
Here is what I did,
I created a separate Transaction.ApproveTable and I attached a trigger on insert, but I am looking them across the sessions
I created an MSMQ journal, but its blocking since its serial from notifying other users. I also have a role notification scenario, where I notify all member of the role.