How would you design a simple chat application using microservices? - microservices

So let's say these are my tables:
users
id(pk) | username
channels
id(pk) | title
members
user_id(pk, fk) | channel_id(pk, fk)
messages
id(pk) | channel_id(fk) | sender_id(fk) | text | created_at
From what I read about microservices, they should be able to be deployed by themselves, and have their own database.
I think that means I would have these microservices each running their own SQL instance:
Users Microservice
users
id(pk) | username
Messaging Microservice
channels
id(pk) | title
members
user_id(pk, fk) | channel_id(pk, fk)
messages
id(pk) | channel_id(fk) | sender_id(fk) | text | created_at
I read that to expose these microservices, I should have some sort of REST/GraphQL API for each one, so Messaging Microservice would have things like getChannel(), createMessage(), etc.
So my question is what should I do when I need to access data in another microservice, basically how should they talk to each other? For example, say on my frontend I enter a chat channel and want to display its messages. If I do a getChannelMessages(), this would return me a list of
{
id: 1,
channel_id: 32,
sender_id: 48,
text: 'hello world',
created_at: some unix time
}
At this point, I don't know who sender_id: 48 is, which I need to display. From there, am I supposed to call Users Microservice's API with getUser(sender_id) for every single message or something?
What if a user gets deleted? Feels like I have to do some extra work to reach into the other microservice to delete all of their messages and remove them from channels. Don't things get out of sync?
Lastly, doesn't this seem like a bit overkill if I only have a single frontend? Am I supposed to have a single frontend that talks to each microservice or are my microservices supposed to have their own frontends too? Maybe if this were a web app I could split URLs for each frontend or something, but multiple frontends doesn't make sense to me in the context of say, a mobile app.
Having trouble putting this all together and would appreciate any advice and clarification.

Related

DDD deal with distributed status accross domains

Let's say we have a simple food delivery app. Where client order the food, then restaurant start preparing the food and gives it to the courier who delivery it to the client.
So here we have three different domains and each of this domain have their own order:
client - here client order the food and have the status of the food in preparation | in delivery | delivered
restaurant - here restaurant got its order and has their own status in queue | in preparation | ready to pick up
courier - courier has only two status delivering | delivered
Moreover each of this domain has their own price and other attribute about order:
client - total price (food price + delivery cost + fee)
restaurant - price of food, time of production to give a hind to the client when food will be delivery
courier - cost of delivery
All I want to highlight is that each of the domain has its own order aggregate, so according to DDD we have to keep it in different aggregates even in different microservices:
client - /orders/:id provides the general status of the order and total price to the client.
restaurant - /restaurants/:restaurantId/orders/:id provides the status of the food in restaurant domain and cost.
courier - /couriers/:courierId/orders/:id provides information how much courier earn from this order and how long it took to delivier
But now I met another problem, because client order combines information from other domains (is food still in restaurant or it's being delivery) so I have to gather this information when client asks about its order, but it means that client doesn't have its domain (its own aggregate, total price, discount etc), but if I create order aggregate for the client then I will not keep all information about order in one place (when restaurant give the food to the courier it should also change status of the order in client domain) what is not really according to microservices, because we keep information about the same order in different microservices.
Should I just create one order domain or should I split it to different domain and make these domains communicate between, when something will change in one domain?
One useful approach is to leverage domain events. When the restaurant's view of the state of the order changes, an event describing that change is published. The other services can then update their model of the event (assuming that that change is relevant to that service).
So for instance, we might have:
user creates order via the client service => OrderCreated event emitted
restaurant service consumes OrderCreated event, translates the order for the restaurant (e.g. uses the prices which the delivery app pays the restaurant vs. the prices the delivery app charges the user) => OrderSentToRestaurant event emitted
courier service consumes OrderCreated and begins trying to figure out which courier will be assigned the order and the approximate transport time from pickup to delivery => DeliveryLatencyEstimateMade event emitted
client service consumes OrderSentToRestaurant and updates its order status (for presentation to the user) to in preparation
courier service ignores OrderSentToRestaurant
restaurant service ignores DeliveryLatencyEstimateMade event
client service consumes DeliveryEstimateLatencyEstimateMade and updates its model (delivery time remains unknown)
restaurant informs restaurant service of expected completion time => OrderReadyForPickupAt event emitted
courier service consumes OrderReadyForPickup, refines courier assignment decisions
client service consumes OrderReadyForPickupAt event, combines with the latest latency estimate to present a predicted delivery time to the user
and so forth. Each service is autonomous and in control of its data representation and free to ignore or interpret the events as it sees fit. Note that this implies eventual consistency (the restaurant service will know about when the order is expected to be ready for pickup before the courier or client services know about that), though microservice autonomy already effectively ruled out strong consistency.
When looking at aggregate design in each bounded context (BC), you have to include only the data required to provide the functionality that belongs to that BC. The fact that the restaurant endpoint needs to return some extra data is not a good enough reason to add that data to the order aggregate in that BC.
You can resolve the need for more data in different ways:
The API client can call multiple endpoints to fetch all the data it needs
The API can implement Data Aggregation, by internally querying multiple BCs/microservices and combining them to produce a single more complete response object
Create Read models, which store data from multiple sources into a single "table" in a way that simplifies querying and returning this data. This approach is more complex, but it's very useful when you need to filter and sort by fields belonging to multiple BCs, which is not possible with the previous two approaches.
Another consideration to make is double-checking if your boundaries are correct. Do you really need a Client BC? What business logic does it implement? Maybe Orders are created directly into Restaurant and there is no Client order? Client order could just be a "façade" providing all Restaurant orders belonging to a single client Id?
As a final note, I completely agree with Levi Ramsey's answer that events are the right way to coordinate the different aggregates. They would also be used to create the read models I mentioned above.

Should I create a table in my database to store only one element

I am not sure if there is another option for this so if someone could give me some advice, it would be greatly appreciated!! Keep in mind, I am a new developper so don't be too harsh with the answers.
So basically I'm developing a web application and I want to give the Admin the possibility to change the email address that will receive a copy of all sent emails (it makes sense in the case of the app). So I got this field where I temporarily have an email address, but once the client gets the app, I want them to be able to modify this email address whenever they want to.
My question is: Should I create a table in my database to store only this email address and thus be able to send a request to modify it when the Admin decides to or is there another way to do it?
Edit: Tell me if I should remove the tags or if there are any better tags for this topic!
There is often a "Admin Settings" table in many applications that allows things like this in a key-value pair sort of model.
|Setting |Value |
++++++++++++
| ccEmail |admin#yourapp.com
| othersetting| 3 |

How to handle mail server configuration in spring in multi tenant environment?

I am converting a normal working application to multi tenant application. Currently I have my mail server configured now I am not able to figure out a way to configure multiple mail server per tenant.
I should be able to add mail server on the fly when new tenant is added.
Please help.
We can think of 2 options
Option 1
You can create a table called as TenantSettings in which you can store key-value pairs of data. The value column being straight forward data or json or any format.
In this you can store the data in the following format or we can store the data in the key-value pair like SMTPServer, SMTPPort etc..
----------------------------------------------------------------------------------------------------------------
Id TenantId Setting Value CreatedBy CreatedOn ......
----------------------------------------------------------------------------------------------------------------
1 123 SMTPConfig {SMTPServer..}
----------------------------------------------------------------------------------------------------------------
2 124 SMTPConfig {SMTPServer..}
----------------------------------------------------------------------------------------------------------------
Option 2
We can store the tenant specific settings inside the tenant specific database itself if you are having a tenant wise database so that once tenant is identified, we can load all the settings for the tenant and use wherever required.
If you can share more details on your current models, we can build a right approach.

Microservices for shared basic lookup data

I am new to microservices, and I need to create a "Student" service, which will get, save and also adds via a webhook from another thirdparty application
However, one of the fields i need to save is "Subject"
Normally, in SQL i would have a subject table, with things like
ID | Subject
1, Maths
2, English
3, Software
which i can use to populate drop down boxes, and in my Student table, i could have "SubjectId" field
However, if using a microservice... how would i setup my student microservice database so its independent?
then, what if I have a "CollegeCourse" service, which also needs the Subject type?
Should they both have there own 2nd database table, but doesnt that run the risk of a miss match... or maybe a nugGet package and just hardcode some enums which i can share between microservices?
Thank you
I can seem to find any suggestions or answers anywhere for this, but,

Messaging with two user tables in Laravel

I am developing a system in which it will have a chat system between two user tables: the clients and the engineers. My problem is how to make these two tables communicate in one message table with regard to registering the sender ID and recipient ID since both can change and are in different tables.
My initial thought for this was two tables where I would use the polymorphic relationship:
chats
id
client_id
engineer_id
messages
id
chat_id
senderable_id
senderable_type
receiverable_id
receiverable_type
content
What would be the most recommended way to solve this problem?
First of all, the following its the generic way that I see to create a chat schem. It'll works to a chat with 2 users or more than 2 users.
Note, the user_chat table its the pivot table between users and chats. You can define an alias to that table, like "participants", because it what it means. You can add more attributes to chats table, but basically need to know the creator.
Finally, the secret in messages table is just to get the sender id from users table, because sender and receiver are relative concepts in this context.
Another more simple and reduced way to do it (if you are trying to make a chat with only 2 users) is:

Resources