-3

I have a batch apex that is facing the error "First error: Apex CPU time limit exceeded".

This batch is collecting account records based on some conditions and then trying to group them using a map with a custom field as the key. I am using Database.Stateful. Any help with the code will be highly appreciated.

Here is my code.

global class AccountFindDunsBatchable implements Database.Batchable<sObject>, Database.Stateful {
    
    global Set<Id> acntsToExclude;
    global Set<Account> accToUpdate = new Set<Account>() ;
    global Map<string,List<Account>> groupedAccountsMap = new Map<string,List<Account>>();\\\
    
    global AccountFindDunsBatchable(Set<Id> excludeAcntsList){
        //Recieved from another batch. These accounts to be excluded in this batch processing.
        this.acntsToExclude = excludeAcntsList;  
    }
    
    global Database.QueryLocator start(Database.BatchableContext bc) {
       String query = 'SELECT  Id FROM Account WHERE '
                        + 'D_B_Match_Score_Confidence_Code__c = \'xx\' AND '
                        + 'RecordType.Name = \'xxxxxx\' AND '
                        + 'Gainsight_to_Process_Date__c=null AND '
                        + 'CreatedById != \'xxxxx\'  AND '
                        + 'LastModifiedById != \'xxxxxx\' AND ' 
                        + 'Exclude_from_Automatic_Deduplication__c!=true AND '
                        + 'Id NOT IN :acntsToExclude ';
       return Database.getQueryLocator(query);  
    }

    global void execute(Database.BatchableContext bc, List<Account> acntsInScope){
        /* 
        List<Account> acntList = new List<Account>();
        Boolean excludeAcc=false;
        //Excluding accounts with IDs received from previous batch
        for(Account ac: acntsInScope){
            for(Id id: acntsToExclude){
                if(ac.id == id){
                    excludeAcc=true;
                }
            }
            if(!excludeAcc){
                acntList.add(ac);
            }
        }*/

         //Grouping remaining accounts based upon a custom field. This map will be used to find master 
         //accounts for each group of accounts
         for(Account account: [SELECT  Id, LastModifiedDate, Master__c, Primary__c, DNBoptimizer__DNB_D_U_N_S_Number__c, is_fp_master__c, fp_master_id__c, to_be_merged__c
                                        , (SELECT Id from Assets limit 1), (SELECT Id from Portal_Groups__r limit 1),
                                         (SELECT Id from Contacts limit 1), (SELECT Id from Cases limit 1), (SELECT Id from Opportunities limit 1),
                                         (SELECT LastModifiedDate from ActivityHistories ORDER BY LastModifiedDate DESC limit 1) 
                                         FROM Account WHERE Id in :acntsInScope]) {
            if(groupedAccountsMap.containsKey(account.DNBoptimizer__DNB_D_U_N_S_Number__c)) {
                // Account already in map
                groupedAccountsMap.get(account.DNBoptimizer__DNB_D_U_N_S_Number__c).add(account);
            } else {
                // Account is not yet in Map
                groupedAccountsMap.put(account.DNBoptimizer__DNB_D_U_N_S_Number__c, new List<Account> { 
               account });
            }
        }
    }

    global void finish(Database.BatchableContext bc){
        
        //Run the logic to find master and duplicate accounts for each group of accounts.
        for (String key : groupedAccountsMap.keySet()) {
            List<Account> accountList = groupedAccountsMap.get(key);
            if(accountList != null && accountList.size()>1){  
                AccountFindPrimary afp = new AccountFindPrimary();
                accToUpdate.addAll(afp.markPrimaryAccounts(accountList));
            }
        }
      Database.executeBatch(new AccountUpdatePrimaryBatchable( accToUpdate ), 20);
    }
}
6
  • 3
    Your loop to check the scope for acntsToExclude is not efficient. How about you modify your query string to exclude these account Ids from the query, so then you don't need to filter them out in your execute()? – Jeremy Nottingham May 2 at 2:37
  • 1
    I should add: Is the exception coming from the execute() or the finish() method? – Jeremy Nottingham May 2 at 2:39
  • @JeremyNottingham I updated the code. 1. I forgot to add subqueries in the for loop while posting the question. So updated that. These subqueries are required as I am checking existence of at least 1 Asset, Contact etc. for accounts in my logic. 2. As you suggested, I removed the loop for acntsToExclude and modified the query string in start method. When I executed the batch (size 100), it initially showed 2735 batches but after reaching at 432, the total count start dropping at came down to 432. No issue faced but any idea why total count dropped after start of the batch? – farooq.ind May 2 at 9:32
  • @JeremyNottingham please see above comment – farooq.ind May 2 at 20:13
  • It sounds like you are asking a new question now. Is the original question resolved? If not, please respond to my other comment regarding when you are getting the exception. If so, please add an Answer with your resolution and start a new Question. – Jeremy Nottingham May 4 at 12:42
1

As After removing the code to check acntsToExclude from execute method and adding the condition in query string in start method as below, exception is not occurring anymore.

 global Database.QueryLocator start(Database.BatchableContext bc) {
       String query = 'SELECT  Id FROM Account WHERE '
                        + 'D_B_Match_Score_Confidence_Code__c = \'xx\' AND '
                        + 'RecordType.Name = \'xxxxxx\' AND '
                        + 'Gainsight_to_Process_Date__c=null AND '
                        + 'CreatedById != \'xxxxx\'  AND '
                        + 'LastModifiedById != \'xxxxxx\' AND ' 
                        + 'Exclude_from_Automatic_Deduplication__c!=true AND '
                        + 'Id NOT IN :acntsToExclude ';
       return Database.getQueryLocator(query);  
    }

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.