0

I am running APEX Schedule batch job and when the batches run, I am constantly seeing the following error:

System.DmlException: Update failed. First exception on row 0 with id 0033s00001008G8AAI; first error: UNABLE_TO_LOCK_ROW, unable to obtain exclusive access to this record or 200 records:

Here is the code to the schedule Batch job

global class DailyApexSchedule implements Schedulable
{
    public Integer batchSize = 10;

    global void execute(SchedulableContext sc) 
    {

        String query1 = 'select whoid contactId, count(id) result from task where Positive_Connect__c = true  AND whoid != null AND ActivityDate = Last_90_Days group by whoid';
        DynamicBatchApexAR batch1     =   new DynamicBatchApexAR('contactId', 'result', 'Positive_Connects_TR_90__c', query1);

        string query2 = 'select whoid contactId, count(id) result from task where subject like \'%[in]%\'  AND whoid != null AND ActivityDate = Last_90_Days group by whoid';
        DynamicBatchApexAR batch2     =   new DynamicBatchApexAR('contactId', 'result', 'Email_Replies_TR_90__c', query2);

        String query3 = 'select whoid contactId, count(Open_Count__c) result from task where Open_Count__c > 0 AND whoid != null AND ActivityDate = Last_90_Days group by whoid';
        DynamicBatchApexAR batch3     =   new DynamicBatchApexAR('contactId', 'result', 'Email_Opens_TR_90__c', query3);

        String query4 = 'select whoid contactId, count(Number_Of_Clicks__c) result from task where Number_Of_Clicks__c > 0 AND whoid != null AND ActivityDate = Last_90_Days group by whoid';
        DynamicBatchApexAR batch4     =   new DynamicBatchApexAR('contactId', 'result', 'Email_Clicks_TR_90__c', query4);

        String query5 = 'select whoid contactId, count(id) result from task where Positive_Connect__c = true  AND whoid != null AND ActivityDate  = LAST_N_DAYS:30 group by whoid';
        DynamicBatchApexAR batch5     =   new DynamicBatchApexAR('contactId', 'result', 'Positive_Connects_TR_30__c', query5);

        string query6 = 'select whoid contactId, count(id) result from task where subject like \'%[in]%\'  AND whoid != null AND ActivityDate  = LAST_N_DAYS:30 group by whoid';
        DynamicBatchApexAR batch6     =   new DynamicBatchApexAR('contactId', 'result', 'Email_Replies_TR_30__c ', query6);

        String query7 = 'select whoid contactId, count(Open_Count__c) result from task where Open_Count__c > 0 AND whoid != null AND ActivityDate  = LAST_N_DAYS:30 group by whoid';
        DynamicBatchApexAR batch7     =   new DynamicBatchApexAR('contactId', 'result', 'Email_Opens_TR_30__c', query7);

        String query8 = 'select whoid contactId, count(Number_Of_Clicks__c) result from task where Number_Of_Clicks__c > 0 AND whoid != null AND ActivityDate  = LAST_N_DAYS:30 group by whoid';
        DynamicBatchApexAR batch8     =   new DynamicBatchApexAR('contactId', 'result', 'Email_Clicks_TR_30__c', query8);

        String query9 = 'SELECT id, Accountid, CreatedDate FROM Opportunity WHERE ( IsClosed = False or CloseDate = TODAY ) AND ( RecordType.name = \'Expansion\' OR  RecordType.name = \'Conversion\' OR RecordType.name = \'New Business\' OR RecordType.name = \'Pre Opportunity\' OR RecordType.name = \'Pre Platform Discussion\' )';
        BatchCampaignInfluence batch9 = new BatchCampaignInfluence(query9);

        Database.executeBatch(batch1, batchSize);
        Database.executeBatch(batch2, batchSize);
        Database.executeBatch(batch3, batchSize);
        Database.executeBatch(batch4, batchSize);
        Database.executeBatch(batch5, batchSize); 
        Database.executeBatch(batch6, batchSize); 
        Database.executeBatch(batch7, batchSize); 
        Database.executeBatch(batch8, batchSize); 
        Database.executeBatch(batch9, 10); 

    }
}

What I think is happening here is that the batches are running at the same time and the record is locking. How can I run a batch when it is finished?

For example, what I think needs to happen is batch2 can only run if batch2 is complete.

3

Sure. You can chain into a second batch from the finish() method of your first batch, and into a third from the second, and so on and so forth.

Starting with API version 26.0, you can start another batch job from an existing batch job to chain jobs together. Chain a batch job to start a job after another one finishes and when your job requires batch processing, such as when processing large data volumes. [...]

You can chain a batch job by calling Database.executeBatch or System.scheduleBatch from the finish method of the current batch class. The new batch job will start after the current batch job finishes.

One way to accomplish this, provided that your batches' instance variables are all serializable, is to code each batch to store a List<Database.Batchable> as an instance variable. You'd assign that variable in the first batch in the sequence with the list of all future batches.

Each batch, in finish(), can pop the next batchable off the list, pass it the remainder of the list, and then enqueue it for execution.

4
  • I understand what you are saying, but from a practical standpoint, I am struggling to understand how to code this solution. Would I have a list of Database.executeBatch(batch2, batchSize);? – Matthew Metros Jul 21 '20 at 22:34
  • One minor point - to have the batchable receive state that is used in the execution (not just the constructor), that state has to be serializable since the batch instance is always serialised into the database by Database.executeBatch and deserialized before the calls to start, execute and finish and, if stateful, re-serialized after the calls to start and execute. – Phil W Jul 21 '20 at 22:37
  • @MatthewMetros the idea is to hold the list of instances, and have finish pop the first batchable off the front of the list, passing it to Database.executeBatch. – Phil W Jul 21 '20 at 22:41
  • @PhilW Is there a resource you recommend for learning more about chaining batch jobs – Matthew Metros Jul 21 '20 at 22:45

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.