[SalesForce] How to re schedule a batch if already 5 apex batch jobs are running

I am trying to schedule a batch after 15 mins from my post installation script which take 100 records and process it. But it might be possible that when my scheduled job will start already another 5 jobs are running or in queue in that case i want to reschedule my batch for next 15 mins.

I am not sure where to put this check which will count no of running apex jobs.

My post installation script contain below code.

       String  batchqueryString = 'Select ID, Account__c,InstanceList__c from CustomerInfo__c';
                         BatchHandler bhObj              = new BatchHandler();
                         bhObj.queryStr                  = batchqueryString;
                         bhObj.batchMethodName           = 'abc';

                   system.scheduleBatch(bhObj,'Scheduleabc',15,100);

Should i write logic to check counts of apex jobs running in BatchHandler execute function and if jobs running are less than 5 then proceed other wise create a new scheduler with same name for next 15 min.

Best Answer

I use this pattern, i've seen lots of others but all do something similar:

private static Integer getCurrentJobCount()
{
    return (Integer)[Select count() From AsyncApexJob Where JobType = 'BatchApex' and ( Status = 'Processing' or Status = 'Preparing' )];
}

private void submitJob( IReschedulable job, SchedulableContext SC )
{
    if( getCurrentJobCount() > 4 )
    {
        // try again in 15 minutes
        Datetime sysTime = System.now().addSeconds( 900 );

        String chronExpression = '' + sysTime.second() + ' ' + sysTime.minute() + ' ' + sysTime.hour() + ' ' + sysTime.day() + ' ' + sysTime.month() + ' ? ' + sysTime.year();

        System.schedule( job.getJobName() + sysTime, chronExpression, (System.Schedulable)job );
    }
    else
    {
        Database.executeBatch( (Database.Batchable<Object>)job, job.getBatchSize() );

        // abort scheduled job if this was as a result of a reschedule
        if( SC != null && job.getAbortAfterSubmit() )
        {
            System.abortJob( SC.getTriggerId() );
        }
    }
}

I've missed off some particulars, but hopefully you get the gist. You should basically put the count just prior to calling Database.executeBatch, which I'm guessing is in the BatchHandler class. I'm afraid it's not completely infallible, because there is of course a moment between the query returning < 4 and the job actually starting (at which point another job could have gotten in) but I've found it to be very reliable (and have it deployed in many orgs).

PS. Just noticed you're using System.scheduleBatch, I personally wouldn't trust that to be safe, see this post.