Server Farm Lock (asp.net)

I would like to know if there is a way to perform a β€œlock” on an asp.net web application that is deployed on multiple servers using a distributed server such as MySQL Cluster.

For example, take the classic example of updating your account balance. Two requests should not update the same account balance at the same time. For instance:

The balance of the account of participant 1 is 100.

  • Request Access to server 1 to add 100 to member balance 1
  • Request B accesses server 2 to add 50 to member 1 balance

Thus, query A updates the balance from 100 to 200 and saves.
Request B updates the balance to 150 and saves.

All this happens exactly at the same time, thus losing information, since the final result should be 250.

How can one block such that request B should wait until request A is completed until it regains balance. If this was the only process, this could be done by blocking the application. However, since there are several independent processes, this will not work, since it is not blocked for server 1, and neither server 2

Any ideas or best practices on how to do this?

+4
source share
3 answers

What are transactions for?

Wrap operations that must be atomic in TransactionScope to register them in an explicit transaction.

This does not completely fix the obsolete data problem, since as soon as the transaction completes, if another concurrent user uses the old value for the update, you still have the problem.

The solution is to use a field in the table that changes whenever the row changes. In SQL Server 2008, this is rowversion .

You only update the row if rowversion not changed - if there is one, you notify the user and return the current values ​​without updating.

+4
source

In the ORM that I created, I implemented a locking mechanism. Each type of object, for example Product, Customer, etc., has 2 additional fields: "LockedBy (int)" and "LockedAt (datetime)".

LockedBy contains the identifier of the user who locked the object, and lockedAt contains the timestamp at which it was locked.

So, when the user wants to start editing the entity, the code goes through this process:

Get an object from the database, '1' is the ProductID

 Product p = new Product(1); 

Lock object for current user

 entity.Lock(); 

To save / fix the object in the database, Save () calls the LockCheck () function, which returns true if the registered user has permission to save the object.

 entity.Save(); 

The user has permission to save the object if:

  (LockedBy < 0 || LockedBy == LoggedInUser.UserID || LockedAt < DateTime.Now.AddMinutes(-30)) 

Note. Users can edit objects that were locked more than 30 minutes ago. If another user has an entity open (on the editing screen), then every 15 minutes it pops up and asks if the user remains there, if so, then he makes a request that increases LockedAt to Now (for example, rolling lock)

At this moment, no other user can edit this object!

The code / user can freely edit this object as much as he wants, and be sure that he has not changed behind him :)

As soon as the user has stopped editing code calls:

 entity.Unlock() 

then

 entity.Save() 

this frees the object for other users to edit it

+1
source

A system such as the Redis' pub / sub mechanism can help you here. Essentially, this is a way to send a message to subscribers (other servers with load balancing) so that they know that an event has occurred. The ServiceStack Redis client has full support for this.

+1
source

Source: https://habr.com/ru/post/1387390/


All Articles