concurrency and atomicity Asp.net core web api and efcore
let's say there's an endpoint called AssingUser() ,this endpoint assigns one donation to this current user who requested it, the idea is that , in the mobile application front end, the view of assignment is shared between many users , so let's say two users clicked at the same time to be assigned to this current donation, how can i make sure that one and only one is able to be set at this same time ? I'm not sure if i delivered what i want clearly 😅
20 Replies
There are a ton of solutions to this, naturally.
The simplest way is to just query the object status before doing the actual assigning, thus checking that the status is still available
Some databases support this
select * from X where Y for update
. What that does is return a result that is locked on a row-level, meaning that returned result cannot be changed by other transactions. This should equate to an optimistic locking, which I think is sufficient for your usecase.
The big benefit to this is that it happens in the same transaction as you fetch the entry, meaning you don't need two roundtrips to a) get the entry b) update its status, because it will be locked by that point.yeah but can't the two requests be reading the same record at the same time ? or is the record automatically locked when some other transaction or query is reading it?
looks nice , im using efcore with Sql server , any idea how to use this facility ?
Sure, and there are ways to solve that. Row locking on the database, or using something like Redis to acquire a shared lock, etc
It all depends on what you are using and how your application is structured and scaled
let me clarify my concerns :
let's say the logic is like that :
- request comes
- check if there's a user assigned to this donation
- if not, assign this current user(update the record )
- if it's already assigned, return bad request
-----------
my concerns are :
both requests read that record and it isn't assigned yet,
both will want to update this record
No I understand. The timing window for that is very small but its possible.
And if that 100% must not be allowed, there are many ways to solve it. I suggested a few above.
Another one is with an E-tag, a column on the database where each row has some randomly generated value
when you fetch it, you read the e-tag. you then include the e-tag in your update statement
if the update fails, the etag has changed and you need to re-check if you still can access it
wait I'll try to understand this 😅
the only way to get the e-tag is to read it from the database. any edit to the row also updates the e-tag 🙂
this is how document databases deal with this scenario, usually
aaah ,like a unique stamp for like "who read this record"
sure
cool idea
Alright thank you pobiega
anyone interested on how i (not me efcore did) solved this problem ?
sure
okki
so
i just added this ðŸ˜
ðŸ˜
The Fluent API IsConcurrencyToken Method
Usage of the Fluent API IsConcurrencyToken Method in Entity Framework Core
Ah, its essentially an e-tag
yes
if combined with
.ValueGeneratedOnAddOrUpdate()
its even automated. nice.but i was shocked how easy to implement it
yeee
in my case i don't want it to generat a value when reading
or when writing
so i just used IsConcurrencyToken