Well I was trying to Implement Record Locking apex but Salesforce Document doesn't seem to help much. Even tried searching stackexchange there was a old question but the answer form StackExchange and details from document seems to be conflicting.
Salesforce Document Link : http://www.salesforce.com/us/developer/docs/apexcode/Content/langCon_apex_locking_statements.htm
StackExchange Question Link : SOQL Record Locking (FOR UPDATE)
According to Salesforce Doc whenever a second transaction tries to lock a record that is already locked it will throw an "QueryException" whereas from the Stackexchange it seems like the second thread will actually wait.
Q1: I am bit confused about what will happen ? Will it fail(throw exception) or will it wait for 4-5 seconds and then if it doesn't get access it will throw an exception ?
In production we are facing a issue where second thread seems to get access to the record even though we have put a lock, second transaction seems to get access, may be after sometime but doesn't seems to throw any exception immediately. For example we have a method
public static void updateMyAccount(){
Account acc = [SELECT Id FROM Account WHERE isValid = TRUE AND Id='SOME ID' FOR UPDATE];
//some time consuming process...callouts etc here
acc.isValid__c = false;
update acc;
}
Scenario:(assuming the system waits)
- Lets assume Thread 1 calls the above method and acquires a lock on the RECORD.
- Now while Transaction 1 is processing the record another Thread Transaction 2 tries to access the record and waits for the lock to release
- While the transaction 2 is waiting thread one changes "isValid__c" to false and the record no more matches the query condition.
Q2 : In the above case will the second thread get access to the record ? or the query will not return any record ?
Q3 : When does the lock gets released ? the Salesforce doc doesn't seems to provide much insight into it. does the lock get released after a DML ? or it waits for full transaction to complete ?
Update 1: Actual Production Scenario In production leads are generally created using web to lead form. We have a page with a button that assign records by pulling records from a queue and changes owner to the current user.
The query looks like
Lead l = Database.query('SELECT Id,Name ,CreatedDate FROM Leads__c WHERE Lead_Status__c =\'Open\' AND Owner.Name = 'My Queue' LIMIT 1 FOR UPDATE');
//some calculation
l.OwnerId = UserInfo.getUserId();
My assumption was when the second user will try to access the same record(by using the same query) it will throw an error. But some how records are getting updated. There are some suspicious records in production where if I check the history
- User 1 Changed Owner from My queue to User 1 [Same TimeStamp]
- User 2 Changed Owner from User 1 to User 2 [Same TimeStamp]
The above observation makes me suspicious that the code actually waits. But again the docs :( . What makes it really hard is this situation is really hard to replicate and almost impossible.