> Pessimistic locking, the way you want to use it, decreases performance because all reads have to wait until the lock is gone. For the web this is realy a bad thing. Futhor more the chance of a deadlock is every time ahead of you.
Reads should not be locked by a FOR UPDATE lock (http://www.postgresql.org/docs/9.4/static/explicit-locking.html#LOCKING-ROWS). I agree potential dead-locks are a problem if you have slightly complicated hierarchies in your transactions. > And worst of all, such a pessimistic lock can take a undetermined amount of time. During a Request this can lead to timeouts on client site. Handle client timeouts can be a nightmare too. That's only undermined if there is an open transaction which holds that lock for an undetermined time right? Heroku for examples gives only 30 seconds to a db connection but generally you would have to monitor the locks. > In this case I would still use optimistic locking. You can simply call .touch on the associated object (in both transaction), so the lock_version is increased. So if I understand correctly your over-all suggestion is to .touch all Objects involved in validations which otherwise would not have been written to in the current transaction. Although it seems touch updates the updated_at column (this can be worked-around I suppose). One concern here is if there are a number of validations each one has to remember to .touch on the object - and if the same object is used in multiple validations that will touch multiple times in one transaction. On Friday, January 8, 2016 at 7:13:47 PM UTC+8, Dieter wrote: > > In this case I would still use optimistic locking. You can simply call > .touch on the associated object (in both transaction), so the lock_version > is increased. > > Pessimistic locking, the way you want to use it, decreases performance > because all reads have > to wait until the lock is gone. For the web this is realy a bad thing. > Futhor more the chance of a deadlock > is every time ahead of you. > > And worst of all, such a pessimistic lock can take a undetermined amount > of time. > During a Request this can lead to timeouts on client site. Handle client > timeouts > can be a nightmare too. > > But that's only my opinion. > > Am Freitag, 8. Januar 2016 11:29:29 UTC+1 schrieb [email protected]: >> >> Sorry, yes you are correct that was a poor example and for that >> particular condition optimistic locking will validate correctly. On the >> other-hand conditions which use data from a reference but do not update >> that reference will still be able to race .e.g. >> >> A fulfillment has fulfillment_line_item's which check that >> fulfillment.status != 'shipped' to validate a destroy on a >> fulfillment_line_item. This later case will validate on the stale >> fulfillment.status - but since only the fulfillment_line_item (not the >> fulfillment) is to be updated in such a transaction no error will be noted >> even if fulfillment.lock_version has changed (since no update to the parent >> would have been attempted). >> >> >> On Wednesday, January 6, 2016 at 4:27:46 PM UTC+8, Dieter wrote: >>> >>> You problem hast nothing todo with multiple dynos. This race condition >>> can occour as soon as you have multiple workers or threats (whatever your >>> server uses). But >>> its a normal issue and in my point of view you can handle it with >>> optimistic locking just fine. >>> >>> When you use optimistic locking rails prepends on every update und >>> delete (when you use object.destroy) a "AND locking_version=?", >>> object.locking_version. >>> >>> In your case when your #update transaction happens it's gets for >>> instance lock_version 1 and also your #delete transaction gets lock_version >>> 1. >>> >>> Say the #delete transaction is faster so you will get an >>> ActiveRecord::StaleObjectError within you #update action or vice versa. >>> >>> You only have to handle the ActiveRecord::StaleObjectError. Without >>> handling this error the transaction will be rolledback (the slower one) >>> >>> But this is only true as long as you use a Isolation level which does >>> not read UNCOMMITTED data. >>> >>> This should be the default in most cases. >>> >>> You can test it this way (as long as you dont use rails identy map). >>> >>> # use same id for find >>> fulfillment1 = Fulfillment.find 1 >>> fulfillment2 = Fulfillment.find 1 >>> >>> fulfillment1.status = '...' >>> >>> fulfillment2.status = '...' >>> >>> >>> >>> fulfillment1.save! >>> >>> fulfillment2.save! # should raise an exception, take a look at the >>> generated SQL-Statement >>> >>> regards >>> dieter >>> >> -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at https://groups.google.com/group/rubyonrails-core. For more options, visit https://groups.google.com/d/optout.
