Friday, 15 February 2013

ruby on rails - ActiveRecord touch causing deadlocks -


My app uses touch on a large scale to take advantage of the template caching system of Railways is. There is a specific type of work, when I have an app, when many relationships are made between batch in many different things. Occasionally, some of these work results in cascading touch es due to deadlock.

I can code around this code for this scenario where I often see it, but looking at it

To understand it, in a single moment on Twitter Think about two people after each other. They both click on "follow-up", as a result the relationship items are created between them and then touch ed each of their records. If this touch differs:

  1. Process 1 touches user A
  2. Process touches user 2
  3. Process 1 touches user
  4. Process 2 touches user A

Each process is using a database transaction, hence the deadlock will occur.

Am I mistaken that this normal app could work out of my strange batch job scenario? If I am not wrong, then is there a solution? Can I move the touch es to stay outside the transaction in some way?

Updates - More details of the data model

  Follow square follow_to: followers (Last list win is ok to update_at update OK ...) , touch: True right_to: follow-up, touch: Follow the correct end @ u1 = user.find (1) @ U2 = user.fid (2) #background job1. Create! (Followers: @ U1, follow-up: @ U2) # Follow the background job 2. Create! (Followers: @ U2, Follow-up: @ u1)  

Not sure What this deadlock does, but you can add pessimistic lock on both of the records, until you want to handle them, until another lock is issued, another request will be stopped, ActiveRecord to proceed Release the lock before

  User.transaction do @ u1, @ u2 = User.lock.where (id: [1,2]) # These two records are now locked, other transaction charges # this lane Can not move forward until they get out of the block. Follow! (Followers: @ U1, Follow-up: @ U2) End # LOW Ck has been issued here  

Note: Passing ID: [2 , 1] will not return them in that order, so you have to handle that situation.

Note 2: Lots of locking can affect your overall app performance, since the user model is probably a heavily used model, but I think it all depends on this It does how often it happens.


Update: This is another way that can work, follow the first model, no touch, but instead a after_create

  Follow square follow_to: follower belongs_to: follow-after_create: touch_users def touch_users # no locking and direct database update user. There (id: [follower.id, followee id] ). Update_all (updated_at :: time.now) and end  

Then the controller will do a normal transaction, or not at all, because you do not need it

  Follow. Create! (Followers: @ U1, follow-up: @ U2)  

Note: #update_all Active record calls back in the fire And if you have any after_update methods, you can avoid this method.


No comments:

Post a Comment