TransWikia.com

Batches Running Asynchronously is causing record locking

Salesforce Asked on November 15, 2021

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.

One Answer

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.

Answered by David Reed on November 15, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP