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
Shantanu SrivastavaShantanu Srivastava 

Apex Batch Job stuck in Processing state

I have an apex Batch Job which gets stuck in Processing status when run on more than 20 records, say 50, but runs well if run on 20 or less records.
If the same code is run via the execute anonymous window all the records are updated successfully.
There is no error in debug logs initially but eventually an Internal Salesforce Error can be seen in logs although the Batch Job stays in Processing status.
15:31:29.539 (2539559703)|FATAL_ERROR|Internal Salesforce.com Error
Can someone please help me with what is causing this Salesforce Error?

Salesforce support suggested using transient keyword, but even that didn't work. Keeping the variables as transient is also not solving the problem. I've now removed most of the functionality, have also removed Database.Batchable. I'm clearing the main list after every update.
But still the batch job is getting stuck in Processing. This is very weird as a batch of 50 records cannot exhaust all the resources causing the entire operation to get stuck.

Thanks,
Shantanu
Raj VakatiRaj Vakati
Hi Shantanu  ,

Can you share the code to see what was the issue . I am thinking that there might be chance to issue with code as well 

Thanks,
Raj
 
Shantanu SrivastavaShantanu Srivastava
Hi Raj,

Thanks for the quick response. Here is the code - there might be some unused variables and chance of optimization but still can't see what is causeing the issue. Any help would be appreciated. 
 
global class InactiveOpportunityBatch implements Database.Batchable<sObject> {

    private String query = 'SELECT Id, Name, StageName, CreatedDate, (SELECT IsClosed, Status, ActivityDate FROM Tasks) FROM Opportunity';
    private Date todaysDate = System.today();
    private Boolean sendEmail = false;
    private List<Opportunity> oppsToBeClosed = new List<Opportunity>();
    //private Map<Id, String> oppIdNameMap = new Map<Id, String>();
    private List<String> mailRecipients;
    private Integer lastNDays = 30;

    /*
    //For Testing specific opps
    List<String> OppIds= new List < String > { '0064E000003Hcmo','0064E000003Hd2x'};
    String OppId = '0064E000003Hcmo';
    private String query ='SELECT Id, Name, StageName, LastActivityDate, Owner.ProfileId, Owner.ID FROM Opportunity Where Id IN: OppIds';
    */

    global InactiveOpportunityBatch() {
        setQuery();
    }
    
    public void setQuery(){

        Exclude_User__mdt configSettings = [SELECT Send_Email__c, Limit__c, Mail_Recipients__c, Created_After_Date__c, LAST_N_DAYS__c, Stage_Names__c, Profile_Ids__c, User_Ids__c FROM Exclude_User__mdt WHERE DeveloperName = 'Inactive_Opportunity_Batch'];
        if(configSettings.Mail_Recipients__c != null){
            mailRecipients = configSettings.Mail_Recipients__c.split(',');
        }
        System.debug('>> # mailRecipients : ' + mailRecipients.size() + ' >> email Ids : ' + mailRecipients);
        
        sendEmail = configSettings.Send_Email__c;
        System.debug('>> sendEmail : ' + sendEmail);

        if(configSettings.LAST_N_DAYS__c != null){
            lastNDays = Integer.valueOf(configSettings.LAST_N_DAYS__c);
        }
        System.debug('>> lastNDays : ' + lastNDays);
        
        List <String> userIdList = new List <String>();
        if(configSettings.User_Ids__c != null)
            userIdList = configSettings.User_Ids__c.split(',');
        
        List <String> profileIdList = new List <String>();
        if(configSettings.Profile_Ids__c != null)
            profileIdList = configSettings.Profile_Ids__c.split(',');
        
        String createdAfterDate = '';
        if (configSettings.Created_After_Date__c != null) {
            createdAfterDate = String.valueOf(configSettings.Created_After_Date__c);
            createdAfterDate += 'T00:00:00Z';
        }

        query += ' WHERE StageName IN (' + configSettings.Stage_Names__c + ')';
        if (configSettings.Created_After_Date__c != null)
            query += ' AND CreatedDate > ' + createdAfterDate;//2016-05-03 00:00:00
        //query += ' AND LastActivityDate != LAST_N_DAYS:' + configSettings.LAST_N_DAYS__c;

        String userIdNotIn = '(';
        String profileIdNotIn = '(';
        if (userIdList.size() > 0) {
            for (String userId : userIdList){
                userIdNotIn += '\'' + userId + '\'' + ',';
            }
            userIdNotIn = userIdNotIn.substringBeforeLast(',');
            userIdNotIn += ')';
        }
        if (profileIdList.size() > 0) {
            for (String profileId : profileIdList){
                profileIdNotIn += '\'' + profileId + '\'' + ',';
            }
            profileIdNotIn = profileIdNotIn.substringBeforeLast(',');
            profileIdNotIn += ')';
        }
        if (userIdList.size() > 0)
            query += ' AND Owner.ID NOT IN ' + userIdNotIn;
        if (profileIdList.size() > 0)
            query += ' AND Owner.ProfileId NOT IN ' + profileIdNotIn;

        if (configSettings.Limit__c != null)
            query += ' LIMIT ' + Integer.valueOf(configSettings.Limit__c);    

        try{
            System.debug('>> Query Formed : ' + query);
            List<Opportunity> oppsReturned = Database.query(query);
            System.debug('Opps returned # : ' + oppsReturned.size());
        }
        catch(Exception e){
            System.debug('>> Exception in querying : ' + e);
        }    
        
    }

    global Database.QueryLocator start(Database.BatchableContext BC){
        System.debug('>> Batch Job InactiveOpportunityBatch START');
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, List <Opportunity> scope){
        
        System.debug('>> Batch Job InactiveOpportunityBatch EXECUTE');
        Boolean toBeClosed = true;
        try {
            for (Opportunity opp : scope){
                
                /*
                1- Get the daily date
                2- Check if all activities are completed for an Opportunity
                3- If any Activity is Open >> Check if due date is more than 30 days older than today
                4- Close the Opportunity only if stage = In Negotiation or Proposal
                5- If even 1 Pending Activity exists with Due Date less than 30 days from today, keep the Opportunity Open
                6- If no Task/Activity exists on the Opportunity check if Created Date is more than 30 days old and then close.
                */
                //Set toBeClosed as true by default(id any of the check fails set this as false and don't close the opp)
                toBeClosed = true;
                //Check if any Activity/Task exists for the Opportunity
                if(opp.Tasks.size() > 0){

                    //Iterate thru all Tasks on this Opportunity
                    System.debug('>> Tasks fetched for this Opp : ' + opp.Tasks);
                    for (Task taskInstance : opp.Tasks){
                        //Check if Activity is still open
                        System.debug('>> taskInstance.IsClosed : ' + taskInstance.IsClosed);
                        if(!taskInstance.IsClosed){
                            //Check if Due date is more than 30 days old from today
                            System.debug('>> taskInstance.ActivityDate : ' + taskInstance.ActivityDate);
                            System.debug('>> system.today().addDays(-lastNDays) : ' + system.today().addDays(-lastNDays));
                            if(taskInstance.ActivityDate != null && taskInstance.ActivityDate > system.today().addDays(-lastNDays)){
                                toBeClosed = false;
                                break;
                            }               
                        }
                    }
                }
                //If no Activity/Task exists for the Opportunity-
                //Check if Created Date is more than 30 days old from today
                else{
                    System.debug('>> No Activity found for the Opp : ' + opp.Name);
                    System.debug('>> Opportunity.CreatedDate : ' + opp.CreatedDate);
                    System.debug('>> system.today().addDays(-lastNDays) : ' + system.today().addDays(-lastNDays));
                    if(opp.CreatedDate > system.today().addDays(-lastNDays)){
                        toBeClosed = false;
                    }
                }
                System.debug('>> Opp - ' + opp.Name + '  toBeClosed : ' + toBeClosed);
                if(toBeClosed){
                    opp.StageName = 'Inactive - Closed Lost'; 
                    oppsToBeClosed.add(opp);
                    //oppIdNameMap.put(opp.Id, opp.Name);
                }
            }

            System.debug('>> # of Opps to be closed : ' + oppsToBeClosed.size());

            if (oppsToBeClosed.size() > 0) {

                if(Test.isRunningTest()){
                    for (Integer x=2; x<oppsToBeClosed.size();x++){
                        oppsToBeClosed[x].Name = '0'.repeat(300);
                    }
                }    

                //Update the Opportunites
                //Transient Database.SaveResult[] resultList = Database.Update(oppsToBeClosed, false);
                Database.Update(oppsToBeClosed, false);
                oppsToBeClosed.clear();

                if(!sendEmail){
                    System.debug('>> Send Email Disabled. Exiting Execute...');
                    return;
                } 
            }
        } catch (Exception e) {
            System.debug('>> Error occured in InactiveOpportunityBatch batch ' + e.getMessage());
        }
    }

    global void finish(Database.BatchableContext BC){
        System.debug('>> Batch Job InactiveOpportunityBatch FINISH');
        System.debug('>> Nothing more to do...');
    }

}

 
Raj VakatiRaj Vakati
Use this execute 


 global void execute(Database.BatchableContext BC, List <Opportunity> scope){
        
        System.debug('>> Batch Job InactiveOpportunityBatch EXECUTE');
        Boolean toBeClosed = true;
        try {
            for (Opportunity opp : scope){
                
                /*
1- Get the daily date
2- Check if all activities are completed for an Opportunity
3- If any Activity is Open >> Check if due date is more than 30 days older than today
4- Close the Opportunity only if stage = In Negotiation or Proposal
5- If even 1 Pending Activity exists with Due Date less than 30 days from today, keep the Opportunity Open
6- If no Task/Activity exists on the Opportunity check if Created Date is more than 30 days old and then close.
*/
                //Set toBeClosed as true by default(id any of the check fails set this as false and don't close the opp)
                toBeClosed = true;
                //Check if any Activity/Task exists for the Opportunity
                if(opp.Tasks.size() > 0){
                    
                    //Iterate thru all Tasks on this Opportunity
                    System.debug('>> Tasks fetched for this Opp : ' + opp.Tasks);
                    for (Task taskInstance : opp.Tasks){
                        //Check if Activity is still open
                        System.debug('>> taskInstance.IsClosed : ' + taskInstance.IsClosed);
                        if(!taskInstance.IsClosed){
                            //Check if Due date is more than 30 days old from today
                            System.debug('>> taskInstance.ActivityDate : ' + taskInstance.ActivityDate);
                            System.debug('>> system.today().addDays(-lastNDays) : ' + system.today().addDays(-lastNDays));
                            if(taskInstance.ActivityDate != null && taskInstance.ActivityDate > system.today().addDays(-lastNDays)){
                                toBeClosed = false;
                               // break;
                            }               
                        }
                    }
                }
                //If no Activity/Task exists for the Opportunity-
                //Check if Created Date is more than 30 days old from today
                else{
                    System.debug('>> No Activity found for the Opp : ' + opp.Name);
                    System.debug('>> Opportunity.CreatedDate : ' + opp.CreatedDate);
                    System.debug('>> system.today().addDays(-lastNDays) : ' + system.today().addDays(-lastNDays));
                    if(opp.CreatedDate > system.today().addDays(-lastNDays)){
                        toBeClosed = false;
                    }
                }
                System.debug('>> Opp - ' + opp.Name + '  toBeClosed : ' + toBeClosed);
                if(toBeClosed){
                    opp.StageName = 'Inactive - Closed Lost'; 
                    oppsToBeClosed.add(opp);
                    //oppIdNameMap.put(opp.Id, opp.Name);
                }
            }
            
            System.debug('>> # of Opps to be closed : ' + oppsToBeClosed.size());
            
            if (oppsToBeClosed.size() > 0) {
                
                if(Test.isRunningTest()){
                    for (Integer x=2; x<oppsToBeClosed.size();x++){
                        oppsToBeClosed[x].Name = '0'.repeat(300);
                    }
                }    
                
                //Update the Opportunites
                //Transient Database.SaveResult[] resultList = Database.Update(oppsToBeClosed, false);
                Database.Update(oppsToBeClosed, false);
                oppsToBeClosed.clear();
                
                if(!sendEmail){
                    System.debug('>> Send Email Disabled. Exiting Execute...');
                    // return;
                } 
            }
        } catch (Exception e) {
            System.debug('>> Error occured in InactiveOpportunityBatch batch ' + e.getMessage());
        }
    }
    

 
Shantanu SrivastavaShantanu Srivastava

I don't get this. What exactly have you changed??

I need to break at line 32, why should I loop thruogh all tasks when I've already found one valid task.

for (Task taskInstance : opp.Tasks){
                        //Check if Activity is still open
                        System.debug('>> taskInstance.IsClosed : ' + taskInstance.IsClosed);
                        if(!taskInstance.IsClosed){
                            //Check if Due date is more than 30 days old from today
                            System.debug('>> taskInstance.ActivityDate : ' + taskInstance.ActivityDate);
                            System.debug('>> system.today().addDays(-lastNDays) : ' + system.today().addDays(-lastNDays));
                            if(taskInstance.ActivityDate != null && taskInstance.ActivityDate > system.today().addDays(-lastNDays)){
                                toBeClosed = false;
                               // break;
                            }               
                        }
                    }
Thanks,
Shantanu
CA SFDCCA SFDC
@Shantanu 
You able to get anything about this issue?