1

I have a batch Apex that processes timecards that meet a certain criteria. if the project(parent project) in the timecard has active child projects and the timecard is approved, the time in the timecard is distributed to all the child projects. Some parent projects have 100 to 800 active child projects. The batch apex processes one timecard at a time. But due to the large no .of child projects the batch hits a cpu limit when processing one timecard too. In order to get around the cpu limit error, the timecards having large no .of child projects are processed by a Queueable which chains itself in batches of 30 child projects. The batch processes timecards that have 30 or less not .of child projects. Any thing above this the queueable is initiated from the batch The queueable run in parallel to the batch and everything works well if all the parent projects in all the timecards are unique. Example: If timecard1 has parentproject1 having 100 child projects and timecard2 also has parentProject1. These two timecards will be processed by the queueable and they trip on each when time is distributed to the active child projects and cause the LOCK error mentioned above. I am assuming this happens because the queueables are executing in parallel. This does not happen to the timecards being processed by the batch apex. Can the queueables initiated from the batch be forced to execute serially? OR Is there another way to around this error?

1

You should use a FOR UPDATE query to make sure you have exclusive locks on the records you need to modify. Make sure you lock parents first, and then children, as appropriate. See the Locking Statements documentation for specifics. If you're concerned you won't be able to get a lock in time (you have about 5 seconds), you can query the records in a loop until you get some threshold or successfully lock the records. Time spent acquiring the locks do not count against your CPU time, although there is an ultimate 10 minute transaction limit you should also be aware of.

  • Thank You. couple of questions. 1. Do I need to specifically lock the parents first and then the children?From the documentation it seemed that if the children are locked sales force automatically locks the parent. 2.Question regarding the statement from your answer If you're concerned you won't be able to get a lock in time (you have about 5 seconds), you can query the records in a loop until you get some threshold or successfully lock the records. – Neema Apr 13 '17 at 3:52
  • Continuation.. Does this mean that, first query the records using the 'FOR UPDATE' in a loop .If this results in a 'Query Exception' then lock was not successfully acquired. Set a flag 'lockAcquired=ffalse'. check against this flag in the loop and query until lock is successfully obtained. Is my understanding correct? When you say (you have about 5 seconds), is this time just for getting the lock on the records? – Neema Apr 13 '17 at 4:04
  • @Neema See this question for more information on the lock timeout, but yes, that generally means you can put your query in a try-catch inside a loop with some limit of retries; if you don't get a lock in say, 30 seconds, just requeue your job to run later. Salesforce recommends locking parents before children explicitly, though my understanding is also that parents will be automatically locked at some point. I think it's simply a way to help avoid deadlocks. – sfdcfox Apr 13 '17 at 12:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.