Things get wickedly complex when there actually needs to be a distributed transaction with rollbacks and global order. I worked on an integration where an upstream service publishes multiple events out of order onto a bus, and embedded within those events are actually separate commands that are expected to be replayed in an agreed upon global order. Some commands can break invariants which must be handled gracefully. This ends up with each consuming service implementing a part of Atomic Broadcast (distributed write-ahead log) to maintain order/idempotency. Makes me appreciate the RDBMS, isolation levels and proper boundaries so much more! Another great video!
This is one of the most helpful explanations of a solution for a common design problem I have ever come across. I rewatched so many of your videos to find this one again lol
Almost always the sticky part is people wanting data for UI/Query purposes which is why they think they need data in a specific boundary. That's almost always the hang-up people have.
So that is mostly about DB transactions rather than code level. "Data Consistency Between Microservices" - I thought that is about distributive patterns like SAGA etc.. ahaha
Hi! This looks really great solution! I have 3 questions: 1. How can QuickOrderCommand handler make save to _salesProductRepository if that repository belongs to Sales? Or is this repository a part of Order Microservice? 2. How is the ATP calculated? Is it some kind of daily job that calculates this based on Warehouse data from QuantityOnHand? 3. Do Catalog, Sales and Warehouse in Cap. centric example represent microservices?
Quick Question : Can we not implement a validation for the price? If the ordered price and price-update are in same we shall update the order service with a different status and refund or cancel the order being not the same ? Maybe that will solve the issue of creating a transaction and also creating a new sales contract.
Good approach if your business is only orders, however in an ecommerce app you will probably want price in the catalog service for filtering , reporting, and non order related businesses
The key thing you just mentioned is reporting. Any type of reporting (including UI) is very different then needing data in another boundary for a command (write operation). If you want to query another service for UI composition, that's a different story.
It seams like the solution you propose for consistency is to bring all the data to one database. How about using compensation between ms to maintain consistency?
When you're performing an action within a service, if you have local data cache or call out the other service (RPC), you're going to immediately be inconsistent with the data in your service. There's no way around that (unless you have a distributed transaction). Using a Saga is a good way to orchestrate a business process throughout a system. I've done a video on event choreography and orchestration: ruclips.net/video/rO9BXsl4AMQ/видео.html
Thanks, Derek for your explanation over Db consistency over concurrent request. I understand that we should use right Db isolation schema based on application need. I have still below doubt. Suppose one rest service is OrderManagement and interacting with another service like Payment service and suppose both are using the same Database table with some Db isolation level, still do we need to pass Transaction tx instance from one service call to another service call as a request param. OR only setting desired Db isolation level will help
Okay I know I might be stepping out of bounds of the example given, but, why clutter the order process with inventory status? Why not just set a level of inventory that displays in real-time alongside the product when inventory reaches a predetermined "low" level where the low level of inventory might spur a sale and move the customer along the funnel faster? That precludes an order if and when inventory is down to zero, or moves the potential sale into a rain check category. This also enables a source of data on firm product interest
No you're not out of bounds at all! You're actually exactly to the point of ATP. The inventory isn't a sales problem, it's a purchasing problem. In other words, exactly as you said, you could be showing the ATP in real time along with the product and if there are orders that go beyond the ATP, you likely just end up doing a rain check (backorder) if you can't get the product in the warehouse from the supplier/manufacturer in time. You must of worked in inventory before :) Thanks for the comment.
also if i have diffrent services with own dbs for users and subscription, business need is user must have subscription on signup, so if i create user and than on creating subscription i have got some error or vice versa than what should i do ? i must need to do this use case as single transaction, calling multiple service as single use case and as single transaction ? how ?
Hi Derek; I have one more query suppose we have single database and multiple services interact with same database. If two service set the different DB isolation level..suppose one service set READ_UNCOMMIT and other one use SERIALIZABLE, how the single database will work with these two different isolation level.
Well using a shared database between services isn't a great idea for several reasons. Check this post out as alternative ruclips.net/video/PZm0RQGcs38/видео.html
@@CodeOpinion and @Derek Thanks for your early response. Actaully I understand one service per database approach and use CQRS or SAGA implementation for tx management, Let's suppose we have multiple services with same DB, lets say an employee registration portal which has several services supporting Admin portal and employee portal and both are working on same Employee DB table. at the same time Admin service perform delete operation and employee servce update his/her records and both the service are using different isolation level..I am not sure how the Db behave with different isolation level.
Using your example, SKU is common across microservices. So, what is the best way to validate the SKU exists when creating data say in the warehouse? Do you perform inter micro service calls to check the existance? Or push the validation to the client?
Depends how you want to create that data. If the creation of a new product is done in the catalog, likely an event would be published that each other services would consume so it would have the newly created SKU. So at that point, there's no need to call to validate it's existence.
@@CodeOpinion if microservice A creates a thing with id 1234, and microservice B has its own data related to that thing with id of 1234 in microservice A ... does validation need to occur to make sure that it exists in the other system? So does the warehouse need to check the SKU exists in the other microservice that owns the sku?
@@nickfurness4260 perhaps each service can have their own unique randomly generated ids, and if you need a nice "visual" id for the user, this could be mapped up in a separate service
this video is great, on the contrary it looks a bit complex to me because I am a frontend dev. However, i have been learning and working for one year seems not enough to get there. BUT, this video gives me some more insight. so a GREAT VIDEO! :)
I don't fully understand what the approach is for things like "names" when you have microservices/multiple databases. If you want to display the name of a product in your Warehouse context, then you have to choose between a network call to the Products microservice; or, storing a copy of the name (which seems much more reasonable), but what about if the Catalog user changes the name? Do you have to update all of the other copies of the name property across your multiple contexts? What approach do you take?
Ey, great video Derek. One question though, how do you handle queries to an entity that is splitted between different modules / BC / microservices? Does this splitting by behaviour approach force you to use read models on a separate service?
Depends what you need the query for. If it's for reporting (UI) purposes, then some type of composition is needed. If it's needed for a command, that's the point of this video is that you'll be using immediately inconsistent data if it's coming from another boundary.
you really touch very hard topics, i thought there is a solution you are going to teach us, very difficult to make consistency between multiple service with diffrent db, can you please give some solution implemetation as well ?
The point is you can't or you have to use a orchestration between services and embrace not having consistency apart of your process and account for it.
This is still not ideal UX. Maybe the user added the product to cart 15 mins ago and now orders it. You are just gonna silently change the price under the customer's nose? When the UI loads and shows prices, the UI needs to know what the catalog version was used. Then when adding stuff to cart or making order, the catalog version is passed along. When looking up the price you use the catalog version associated with each ordered product. That way concurrent modifications have no undesirable effect on the user. No need to change where the price data lives just because of this.
Just default settings in Rider. Pretty sure they are "Inlay hints": www.jetbrains.com/help/rider/Inline_Parameter_Name_Hints.html#type-conversion-hints
Have been following you for a while now, and i want to say you have a really valuable content. Thanks! What do you think about reactive programming (in context of microservices ) ?
@@freshone770 Not familiar enough to really comment. Are messages durable? What happens on processing failures? Can you have built in retries or a type of dead letter queue?
@@CodeOpinion It's not a message queue and actually now, when i am thinking about it, RSocket is not a replacement for message queue. So my question was wrong from the beginning 😀
I'm adding a Hypermedia API (Hal+Json). My thought was to add it at a service level. An I have a problem with linking resources across boundaries. Now I think that perhaps I should put my API in a separate app and compose all boundaries in there. I'm not comfortable with it though. Since each service already has a Web API, it can easily get messy with consistency - even if I use async messaging which I would.
I've run into this as well and ultimately it comes down to composition. Regardless if you're generating HTML or JSON, it comes down to wanting to provide a rich response that's composed from various services. That has to happen somewhere!
Things get wickedly complex when there actually needs to be a distributed transaction with rollbacks and global order.
I worked on an integration where an upstream service publishes multiple events out of order onto a bus, and embedded within those events are actually separate commands that are expected to be replayed in an agreed upon global order. Some commands can break invariants which must be handled gracefully. This ends up with each consuming service implementing a part of Atomic Broadcast (distributed write-ahead log) to maintain order/idempotency.
Makes me appreciate the RDBMS, isolation levels and proper boundaries so much more! Another great video!
That does sound like a fun situation! Thanks for the comment, gives others some insight.
Yep, you not only teach us about code architecture, but also business architecture. Great job and thanks!
Thanks!
Man, why are you not getting more views and subs? I love your content!
Thanks for watching it. Please share 😀
Because the titles are not clickbait.... RUclips right!
This is one of the most helpful explanations of a solution for a common design problem I have ever come across. I rewatched so many of your videos to find this one again lol
Almost always the sticky part is people wanting data for UI/Query purposes which is why they think they need data in a specific boundary. That's almost always the hang-up people have.
So that is mostly about DB transactions rather than code level.
"Data Consistency Between Microservices" - I thought that is about distributive patterns like SAGA etc.. ahaha
Orchestration is a way to handle a long running business process. I've covered it in this video: ruclips.net/video/rO9BXsl4AMQ/видео.html
Another way to relieve db call is to use queue. Order serialization and app decoupling can be done by that way.
Hi! This looks really great solution! I have 3 questions:
1. How can QuickOrderCommand handler make save to _salesProductRepository if that repository belongs to Sales? Or is this repository a part of Order Microservice?
2. How is the ATP calculated? Is it some kind of daily job that calculates this based on Warehouse data from QuantityOnHand?
3. Do Catalog, Sales and Warehouse in Cap. centric example represent microservices?
Great explanation. Thank you
Thanks. Hopefully it was helpful.
Quick Question : Can we not implement a validation for the price? If the ordered price and price-update are in same we shall update the order service with a different status and refund or cancel the order being not the same ? Maybe that will solve the issue of creating a transaction and also creating a new sales contract.
Good approach if your business is only orders, however in an ecommerce app you will probably want price in the catalog service for filtering , reporting, and non order related businesses
The key thing you just mentioned is reporting. Any type of reporting (including UI) is very different then needing data in another boundary for a command (write operation). If you want to query another service for UI composition, that's a different story.
It seams like the solution you propose for consistency is to bring all the data to one database. How about using compensation between ms to maintain consistency?
When you're performing an action within a service, if you have local data cache or call out the other service (RPC), you're going to immediately be inconsistent with the data in your service. There's no way around that (unless you have a distributed transaction). Using a Saga is a good way to orchestrate a business process throughout a system. I've done a video on event choreography and orchestration: ruclips.net/video/rO9BXsl4AMQ/видео.html
@7:00 I'm seeing a possible defect in the flow. You're making the quickorder by removing 1 from ATP then the Factory is checking for
Oops! I end up rejigging these examples so many times when I record that I missed that.
Thanks, Derek for your explanation over Db consistency over concurrent request. I understand that we should use right Db isolation schema based on application need. I have still below doubt. Suppose one rest service is OrderManagement and interacting with another service like Payment service and suppose both are using the same Database table with some Db isolation level, still do we need to pass Transaction tx instance from one service call to another service call as a request param. OR only setting desired Db isolation level will help
Okay I know I might be stepping out of bounds of the example given, but, why clutter the order process with inventory status? Why not just set a level of inventory that displays in real-time alongside the product when inventory reaches a predetermined "low" level where the low level of inventory might spur a sale and move the customer along the funnel faster? That precludes an order if and when inventory is down to zero, or moves the potential sale into a rain check category. This also enables a source of data on firm product interest
No you're not out of bounds at all! You're actually exactly to the point of ATP. The inventory isn't a sales problem, it's a purchasing problem. In other words, exactly as you said, you could be showing the ATP in real time along with the product and if there are orders that go beyond the ATP, you likely just end up doing a rain check (backorder) if you can't get the product in the warehouse from the supplier/manufacturer in time. You must of worked in inventory before :) Thanks for the comment.
When would be suitable ,into a DDD projects to use factories?
also if i have diffrent services with own dbs for users and subscription, business need is user must have subscription on signup, so if i create user and than on creating subscription i have got some error or vice versa than what should i do ? i must need to do this use case as single transaction,
calling multiple service as single use case and as single transaction ? how ?
Hi Derek; I have one more query suppose we have single database and multiple services interact with same database. If two service set the different DB isolation level..suppose one service set READ_UNCOMMIT and other one use SERIALIZABLE, how the single database will work with these two different isolation level.
Well using a shared database between services isn't a great idea for several reasons. Check this post out as alternative ruclips.net/video/PZm0RQGcs38/видео.html
@@CodeOpinion and @Derek Thanks for your early response. Actaully I understand one service per database approach and use CQRS or SAGA implementation for tx management, Let's suppose we have multiple services with same DB, lets say an employee registration portal which has several services supporting Admin portal and employee portal and both are working on same Employee DB table. at the same time Admin service perform delete operation and employee servce update his/her records and both the service are using different isolation level..I am not sure how the Db behave with different isolation level.
Using your example, SKU is common across microservices. So, what is the best way to validate the SKU exists when creating data say in the warehouse? Do you perform inter micro service calls to check the existance? Or push the validation to the client?
Depends how you want to create that data. If the creation of a new product is done in the catalog, likely an event would be published that each other services would consume so it would have the newly created SKU. So at that point, there's no need to call to validate it's existence.
@@CodeOpinion if microservice A creates a thing with id 1234, and microservice B has its own data related to that thing with id of 1234 in microservice A ... does validation need to occur to make sure that it exists in the other system?
So does the warehouse need to check the SKU exists in the other microservice that owns the sku?
@@nickfurness4260 perhaps each service can have their own unique randomly generated ids, and if you need a nice "visual" id for the user, this could be mapped up in a separate service
this video is great, on the contrary it looks a bit complex to me because I am a frontend dev. However, i have been learning and working for one year seems not enough to get there. BUT, this video gives me some more insight. so a GREAT VIDEO! :)
Glad it was helpful!
I don't fully understand what the approach is for things like "names" when you have microservices/multiple databases.
If you want to display the name of a product in your Warehouse context, then you have to choose between a network call to the Products microservice; or, storing a copy of the name (which seems much more reasonable), but what about if the Catalog user changes the name? Do you have to update all of the other copies of the name property across your multiple contexts? What approach do you take?
Query/Display/Reporting/UI is a different aspect entirely. UI and ViewModel Composition is a topic I'll cover soon in another video.
Ey, great video Derek. One question though, how do you handle queries to an entity that is splitted between different modules / BC / microservices? Does this splitting by behaviour approach force you to use read models on a separate service?
Depends what you need the query for. If it's for reporting (UI) purposes, then some type of composition is needed. If it's needed for a command, that's the point of this video is that you'll be using immediately inconsistent data if it's coming from another boundary.
you really touch very hard topics, i thought there is a solution you are going to teach us, very difficult to make consistency between multiple service with diffrent db, can you please give some solution implemetation as well ?
The point is you can't or you have to use a orchestration between services and embrace not having consistency apart of your process and account for it.
It was really helpful. That's all I can tell you ))
Thanks!
This is still not ideal UX. Maybe the user added the product to cart 15 mins ago and now orders it. You are just gonna silently change the price under the customer's nose?
When the UI loads and shows prices, the UI needs to know what the catalog version was used. Then when adding stuff to cart or making order, the catalog version is passed along. When looking up the price you use the catalog version associated with each ordered product. That way concurrent modifications have no undesirable effect on the user. No need to change where the price data lives just because of this.
How do you display the explicit type of var in your IDE? I tried finding the setting or extension for it, but I couldn't find it.
Great Videos btw!
Just default settings in Rider. Pretty sure they are "Inlay hints": www.jetbrains.com/help/rider/Inline_Parameter_Name_Hints.html#type-conversion-hints
@@CodeOpinion Yes that was it! They are called inlay hints. Just needed the name to help me find it! Thank you
Have been following you for a while now, and i want to say you have a really valuable content. Thanks!
What do you think about reactive programming (in context of microservices ) ?
Glad you enjoy it. Can you elaborate a bit more on the question?
@@CodeOpinion Using reactive streams like RSocket instead of using some message broker for asynchronous communication between microservices
@@freshone770 Not familiar enough to really comment. Are messages durable? What happens on processing failures? Can you have built in retries or a type of dead letter queue?
@@CodeOpinion It's not a message queue and actually now, when i am thinking about it, RSocket is not a replacement for message queue. So my question was wrong from the beginning 😀
helpful, thank you
You're welcome!
Great videos as always..
Thanks again!
👌👌👌👌👌👌👌
I'm adding a Hypermedia API (Hal+Json). My thought was to add it at a service level. An I have a problem with linking resources across boundaries.
Now I think that perhaps I should put my API in a separate app and compose all boundaries in there. I'm not comfortable with it though. Since each service already has a Web API, it can easily get messy with consistency - even if I use async messaging which I would.
I've run into this as well and ultimately it comes down to composition. Regardless if you're generating HTML or JSON, it comes down to wanting to provide a rich response that's composed from various services. That has to happen somewhere!