Milan, I love how you tackle core production use cases and scenarios that we all face every day, and how you solve them easily. Keep up the awesome work!
Here is a key combo you should start using. In Visual Studio Ctrl-K,S will bring up a context menu that allows you to select the structure with which you will surround the selected text.
Could you please create a video that shows how to handle race conditions when multiple instances of database are involved? For eg: multiple instances of application and multiple instances of database.
I liked your style of presentation but I think you didn't really address the title of your video. It's about distributed locking and you assumed we had to stick to Postgres and after that resorted to a uniqueness index. Well, not every case of distributed locking happens when dealing with a relational database. I was looking for an in-depth explanation of something like the Redlock algorithm and an attempt to implement it.
nice, i didnt knew we could use when statements like these in c#. i have been using unique indexes similar to your solution but i threw whole exception without specifics , thanks.
@@MilanJovanovicTech it's auto increment field not primary+ this will be applied per tenant not global counter. So, there could be itemRefNum=5 with tenant x and itemRefNum=5 with tanant y
Considering your previous videos on using soft delete, this approach can generate errors when a user is deleted and a new user is registered with the same email.
Thanks for your content. I really like it. I have quetion regarding UseCase concept. I dont know if you are basing on clean arch (uncle Bob) cocept. If so, dont you think you are leaking tech/infra details into your usecase, with this implementation?
@@MilanJovanovicTech yeah, thats is the reason I specified if you was baseing on Uncle Bob concept of usecase. From Uncle Bob words: "We do not expect this layer [usecases] to be affected by changes to externalities such as the [database], the UI, or any of the common frameworks. This layer is isolated from such concerns."
I wouldn't call it better, but it's definitely a simpler option if you're already using Postgres. No additional infrastructure needed. If there's no unique field, like in your case, use a lock.
I think....if you use an email verification process, you dont need to lock as it wouldnt be possible to register a duplicate email. You would only have the ability to verify a single email.
And the Users.Exists() check is redundant. By the way, ef core doesn't support unique constraints that makes it impossible to use deferred constraints when needed. Only unique indexes that can not be deferred.
Sorry but isn't the purpose of a lock to ensure that whatever you have beneath it will succeed and not throw exceptions and/or have an invalid state in your data? You check if the email exists but then you depend on the infrustructure to enforce it? this is not simple it's, at best, inefficient, if not prone to ddos attacks use locks and if the app is in many instances just put the lock somewhere accessable for all
Why would you add this extra complexity for a scenario that is really not likely to happen. I'd say near as likely as losing the connection to the db, which will throw also. The goal is not to prevent the error from happening, rather it is to enforce uniqueness. And what better place than the actual place the live in to do it.
@herve952 @joga_bonito_aro @MilanJovanovicTech just to clarify, i am not objecting to having a unique constrain on the db but it is one thing to have something to safeguard your persistant state and another to use this in the app the email uniqueness comes as a business requirement, and as such you must treat it and as early as possible if for the business is a very serious matter, you do a proper lock or a distributed one, if it is something that they don't really care, you just go with the db constrain but in any case you should never let exceptions define the behaviour of your app, an exception raised from classA and an exception raised from classB should always result in the exact same behaviour
Simplify your development process - download my free Clean Architecture template: bit.ly/3Andaly
Thanks Milan, how to address if we need call validation without its command?
I have downloaded the template, is there a docs guidelines?
Hey, Milan how about distributed databases like Cassandra, ScyllaDb, YugabyteDb based on LSM Tree
Milan, I love how you tackle core production use cases and scenarios that we all face every day, and how you solve them easily. Keep up the awesome work!
Thanks a lot! :)
Dear Milan
I like your coding style:)
Thanks, much appreciated! :)
Here is a key combo you should start using. In Visual Studio Ctrl-K,S will bring up a context menu that allows you to select the structure with which you will surround the selected text.
Oh, that'll come in handy. Appreciate the tip!
Could you please create a video that shows how to handle race conditions when multiple instances of database are involved? For eg: multiple instances of application and multiple instances of database.
A distributed transaction? No, screw that 😂
I liked your style of presentation but I think you didn't really address the title of your video. It's about distributed locking and you assumed we had to stick to Postgres and after that resorted to a uniqueness index. Well, not every case of distributed locking happens when dealing with a relational database. I was looking for an in-depth explanation of something like the Redlock algorithm and an attempt to implement it.
I'll cover Redlock in a future (well-named) video!
@@MilanJovanovicTech Thank you. I'm definitely looking forward to it
nice, i didnt knew we could use when statements like these in c#. i have been using unique indexes similar to your solution but i threw whole exception without specifics , thanks.
Yeah, this is one of these useful C# features that not many people know of
Hey guys... someone can tell witch is de milan theme for visual studio? i love it, but didnt figure out...
@@JonathanGabrielSilva it's ReShaper, plus its syntax highlighting :)
he use VS2022 default dark theme, but he also use Resharper so code color is little bit different than the stock one in VS2022
thank you! now my code is almost beautful like milan's code... xP
so, what to do using mssql without unique index and redis in this case ?
Distributed lock of some sorts
what do you think about optimistic lock for same last product ordering by two or more users in a distributed system?
If we already have an entity than optimistic concurrency should be fine
Great video, can you tell me how to handle a use case where new item should have unique auto increment counter?
Database should handle that depending on your database u can check for example SERIAL for postgres
Autoincrementing PK?
@@MilanJovanovicTech it's auto increment field not primary+ this will be applied per tenant not global counter. So, there could be itemRefNum=5 with tenant x and itemRefNum=5 with tanant y
@@ahmedameen2 Is it important for it to be a counter? Each tenant has to start with 1, then 2, etc.?
Yes unfortunately it's a business need @@MilanJovanovicTech
Thanks for the videos amazing content
Most welcome!
Considering your previous videos on using soft delete, this approach can generate errors when a user is deleted and a new user is registered with the same email.
But we're not using soft deletes here?
Try a combination of email and the soft delete flag when creating the index
Summary: use db unique index
TL;DW
@@MilanJovanovicTech 😅😅 I enjoyed it, i'm gonna try the redlock. Thank you
How to use distributed lock in Sql Server instead of Postgre?
There are:
- sp_getapplock (learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-getapplock-transact-sql)
- sp_releaseapplock (learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-releaseapplock-transact-sql)
so we can remove first email check if right?
Yes
What if you're using a database that doesn't support uniqu index like Azure Table Storage or Cosmos Db?
Find a new database 😂
Isn't the problem you stated can be sloved by eTag concept?
Is distributed lock the right approach to solve this concurrency or race condition issue?
How would ETag solve this?
Thanks for your content. I really like it. I have quetion regarding UseCase concept. I dont know if you are basing on clean arch (uncle Bob) cocept. If so, dont you think you are leaking tech/infra details into your usecase, with this implementation?
A use case is a pretty generic concept. One use case = one piece of functionality.
@@MilanJovanovicTech yeah, thats is the reason I specified if you was baseing on Uncle Bob concept of usecase. From Uncle Bob words: "We do not expect this layer [usecases] to be affected by changes to externalities such as the [database], the UI, or any of the common frameworks. This layer is isolated from such concerns."
Is this one better than Redis lock?
Then what should I do if there is no unique field for inventory increase or decrease?
I wouldn't call it better, but it's definitely a simpler option if you're already using Postgres. No additional infrastructure needed. If there's no unique field, like in your case, use a lock.
@@MilanJovanovicTech 👍
In line 28 why have you used add method… when you are trying to update
Am I not creating a new user?
🤣🤣🤣
Hi Milan, thank you for the video. Can you present the same but with the Redis lock?
Yes!
I think....if you use an email verification process, you dont need to lock as it wouldnt be possible to register a duplicate email. You would only have the ability to verify a single email.
Race condition still? Who verifies first?
And the Users.Exists() check is redundant.
By the way, ef core doesn't support unique constraints that makes it impossible to use deferred constraints when needed. Only unique indexes that can not be deferred.
I left it for fail fast principle, but yeah, it's redundant if we handle the concurrency exception
... I was about to say that a unique index was probably a better option in this particular scenario, then you went ahead and did just that. Haha.
There we go 😁
That is indeed picky but true for sure 😅
Which approach would you use?
Sorry but isn't the purpose of a lock to ensure that whatever you have beneath it will succeed and not throw exceptions and/or have an invalid state in your data?
You check if the email exists but then you depend on the infrustructure to enforce it?
this is not simple it's, at best, inefficient, if not prone to ddos attacks
use locks and if the app is in many instances just put the lock somewhere accessable for all
Also factor in the likelihood of a race condition here. It's pretty low. Locks are an overkill for this. Use a unique constraint.
@@MilanJovanovicTech Depending on database exceptions is also an overkill
Why would you add this extra complexity for a scenario that is really not likely to happen. I'd say near as likely as losing the connection to the db, which will throw also. The goal is not to prevent the error from happening, rather it is to enforce uniqueness. And what better place than the actual place the live in to do it.
@@teothe I don't think this is meant for the gigazillion user base application. Rather for a really low user count that is easy to comprehend.
@herve952 @joga_bonito_aro @MilanJovanovicTech just to clarify, i am not objecting to having a unique constrain on the db
but it is one thing to have something to safeguard your persistant state and another to use this in the app
the email uniqueness comes as a business requirement, and as such you must treat it and as early as possible
if for the business is a very serious matter, you do a proper lock or a distributed one, if it is something that they don't really care, you just go with the db constrain
but in any case you should never let exceptions define the behaviour of your app, an exception raised from classA and an exception raised from classB should always result in the exact same behaviour
I know this is picky, but please consider calling an EmailAddress just that, not Email. An Email has a sender, recipient, subject. body etc.
The Email on the User entity?
I hate nitpick commits.
never thought about it that way :o