+ Start a Discussion
snakerootsnakeroot 

Testing Multiple Scheduled Apex Jobs

I'm getting the following error intermittently when running a scheduled batch class:  Attempted to schedule too many concurrent batch jobs in this org (limit is 5). 

I found out why I'm gettting this error and the code to use to maneuver around this limitation in this KB article (https://help.salesforce.com/apex/HTViewSolution?id=000182449" target="_blank).  I'm able to test for the code in the if part of the if/else statement to get code coverage, but I can't figure out how to test the else part of the statement.  If anyone could help me out with this, I'd appreciate it.  Here's the code and the test coverage code: 

Schedulable Class: 
global void execute(SchedulableContext sc) {

	try{	
    	//check if there are 5 active batch jobs
		//In some cases, might need to add "Status='Queued' " to the criteria
		if ([SELECT count() FROM AsyncApexJob WHERE JobType='BatchApex' AND (Status = 'Processing' OR Status = 'Preparing')] < 5){ 
	    	CatchOfTheDayBatch controller = new CatchOfTheDayBatch('SELECT Id,Name,Retention_Target_Name_LOST__c,Retention_Target_ID_LOST__c, Retention_Target_Email_Date_LOST__c,Authorization_Signature__r.Id FROM Account	WHERE RecordType.Name = \'RR Companies\' AND Retention_Target_ID_LOST__c != null ORDER BY Retention_Target_ID_LOST__c DESC');
			Integer batchSize = 10;
			database.executebatch(controller , batchSize);	
		} else {
			//schedule this same schedulable class again in 30 mins
			CatchOfTheDay scheduledClass = new CatchOfTheDay();
			Datetime dt = Datetime.now() + (0.024305); // i.e. 30 mins
   			String timeForScheduler = dt.format('s m H d M \'?\' yyyy');
   			Id schedId = System.Schedule('MatrixRetry'+timeForScheduler,timeForScheduler,scheduledCLass);	
		}
	}
	catch (System.EmailException e) { System.debug('An error has occurred: '+e); }
	} 	

}

Test Code: 
@isTest
                                
private class Test_CatchOfTheDay {


   public static String CRON_EXP = '0 0 0 15 3 ? 2022';

   static testmethod void test() {
      Test.startTest();


      String jobId = System.schedule('CatchOfTheDay',
                        CRON_EXP, 
                        new CatchOfTheDay());
         

      CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, 
         NextFireTime
         FROM CronTrigger WHERE id = :jobId];


      System.assertEquals(CRON_EXP, 
         ct.CronExpression);


      System.assertEquals(0, ct.TimesTriggered);


      System.assertEquals('2022-03-15 00:00:00', 
         String.valueOf(ct.NextFireTime));
      Test.stopTest();

   }
}



 
snakerootsnakeroot
Update:  I tried scheduling more than 5 BatchApex jobs and then running the code to handle more than 5 BatchApex jobs, but because the creation of all the scheduled jobs happens as soon as Test.StopText(); executes, an error is thrown stating there are more than 5 BatchApex jobs scheduled.  Any tips on how to test for this is much appreciated.  I'm stumped. 
snakerootsnakeroot
I was way off in left field on this one.   I got some help and through a lot of experimenting this is what ended up working with 100% test coverage (in case it helps someone down the road): 

Scheduleable class: 
lobal void execute(SchedulableContext sc) {

	try{	
    	//check if there are 5 active batch jobs
		//In some cases, might need to add "Status='Queued' " to the criteria
		
    	Integer enqueuedJobs = numBatchApexInQueue();
		if (enqueuedJobs < 5){ 
	    	CatchOfTheDayBatch controller = new CatchOfTheDayBatch('SELECT Id,Name,Retention_Target_Name_LOST__c,Retention_Target_ID_LOST__c, Retention_Target_Email_Date_LOST__c,Authorization_Signature__r.Id FROM Account	WHERE RecordType.Name = \'RR Companies\' AND Retention_Target_ID_LOST__c != null ORDER BY Retention_Target_ID_LOST__c DESC');
			Integer batchSize = 10;
			database.executebatch(controller , batchSize);	
			System.debug('after ='+ numBatchApexInQueue());
		} else {
			
			//schedule this same schedulable class again in 30 mins
			System.debug('Entering else');
			CatchOfTheDay scheduledClass = new CatchOfTheDay();
			Datetime dt = Datetime.now().addMinutes(30);
   			String timeForScheduler = dt.format('s m H d M \'?\' yyyy');
   			String scheduleName = 'COTDRetry '+timeForScheduler;
			Id schedId = System.Schedule('COTDRetry '+timeForScheduler,timeForScheduler,scheduledClass);
		}

	}		
		catch(Exception e){
         Boolean expectedExceptionThrown = e.getMessage().contains('already scheduled for execution');
         System.AssertEquals(expectedExceptionThrown, true);
      }

	} 

	public static Integer numBatchApexInQueue() {
		return [SELECT count() FROM AsyncApexJob WHERE JobType='BatchApex' AND (Status = 'Processing' OR Status = 'Preparing' OR Status = 'Queued')];
	}

}

Test class:
@isTest
                                
private class Test_CatchOfTheDay {

   // CRON expression: midnight on March 15.
   // Because this is a test, job executes
   // immediately after Test.stopTest().
   public static String CRON_EXP = '0 0 0 15 3 ? 2022';

   static testmethod void beginTest(){
      
      Test.startTest();
         try{
            testnumBatches('Test2',6);  //schedule more than 5 to test both the If and Else portion of the CatchOfTheDay class
         }catch(Exception e){
            Boolean expectedExceptionThrown = e.getMessage().contains('already scheduled for execution');
            System.AssertEquals(expectedExceptionThrown, true);
         }
      Test.stopTest();
   }

   static void testNumBatches(String name,Integer numBatches) {
      String sch = '0 27 05 * * ?';
      for(Integer i=1;i<=numBatches;i++){
            // create x  number of different batch jobs                      
            CatchOfTheDay COTD = new CatchOfTheDay();      
            system.schedule(name+i.format(), sch, COTD);
            COTD.execute(null);   
        }
      
   }
}