function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Jake GmerekJake Gmerek 

Avoiding governor limits while avoiding a race condition

We have an interesting scenario that is keeping us from having good test coverage in our Org and I am looking for ideas on how to fix it:

 

Essentially the pseudocode goes like this:

 

listofLeads = Select stuff from lead where conditions are met and order by some criteria;

 

for (lead l: listofLeads){

   

   leadtoGet = select stuff from lead where id = l.id limit one for update

   if(leadtoGet is not NULL){

        update lead owner to current user

         break

   }

}

 

So the issue is obvious we have a SOQL query in the for loop.  In production we have no problems because there is a small enough number of users that there are few leads locked at any given time and once an unlocked lead is found the break gets us out of the loop and avoids governor limits.  However in testing this on 200 hundred records it loops more than enough times to hit the SOQL query limit.  As a work around a custom setting has been implemented that disables this entire block of code.  This allows the test to pass.

 

Unfortunately, this is actually replicated for 4 separate criteria and results in a large block of code that does not get tested and brings down our overall test coverage.  Also we are considering merging another org into this one that would increase the number of users by an order of magnitude and that could pose a problem as well, so we would like to refactor this code, but we are stuck.

 

Any ideas would be appreciated.

Andrew WilkinsonAndrew Wilkinson

//Put the ids of the list in a set.

Set<Id> leadIds = new Set<Id>();

for(lead l : listofLeads)

leadIds.add(l);

 

//Then query using those Ids and put them in a map

Map<Id,Lead> leadMap = new Map<Id,Lead>();

 

for(Lead l : [the query inside your for loop WHERE ID IN :leadIds])

leadMap.put(l.id,l);

 

//then set your leadtoget to the value from the map

leadtoGet = leadMap.get(l.Id);

Jake GmerekJake Gmerek

Andrew,

 

Normally that is exactly how I would approach the situation.  However, in this case, since I am using the FOR UPDATE key words in the SOQL query, if I did it the way that you suggest, it would lock the entire set of leads.  So if another user went to grab a lead while the first user was still working, all the leads would be locked and the second user would have none to grab.  It makes for an interesting issue.

 

Thanks for the help though!!