+ Start a Discussion
Radhe ShyamRadhe Shyam 

How to schedule apex class after every 5 minutes

Here is my apex batch:

global class EmailAlertToQuoteProposalApprovalUser implements Database.Batchable<sObject>, database.stateful{
    
    public String EVENT_TYPE_MEETING = 'Meeting';
    private Datetime EndTime=System.now();
    private String query;
    public String limitSize;
    private long recordcount;
    private string debuglog='';
    private integer batchcounter=0;
    private datetime processstarttime=system.now();
    private boolean haserror=false;
    private set<id> processedaccounts=new set<id>();
   
    global EmailAlertToQuoteProposalApprovalUser(datetime activitydatetime){
        if(activitydatetime==null){
            EndTime=System.now().adddays(-1);
        }
    }
   
   global Database.QueryLocator start(Database.BatchableContext BC){
       log('Batch process start time: ' + processstarttime);
       log('Batch process id: ' + bc.getJobID());
       log('Acvitity End Time Parameter: ' + EndTime);
       Datetime dtTimeNow=system.now();
       query='SELECT Id,Pending_With_Email__c,Submitted_Date_time__c FROM Apttus_Proposal__Proposal__c WHERE Submitted_Date_time__c!=null AND Submitted_Date_time__c>=: dtTimeNow' + ' ORDER BY Id';
       if(limitSize!=null)
       {
        query = query + ' LIMIT ' +  limitSize;
       }     
            
       log(query); 
       return Database.getQueryLocator(query);                                    
      
    }
   
    global void execute(Database.BatchableContext BC, List<sObject> scope){
        log('Batch number: ' + batchcounter);
        set<id> QuoteProposalId=new set<id>(); 
        list<Apttus_Proposal__Proposal__c>  lstQuoteProposal=new list<Apttus_Proposal__Proposal__c>();
        for(sobject so: scope){
            id quoteid=(Id)so.get('Id');
            Apttus_Proposal__Proposal__c objQuote= (Apttus_Proposal__Proposal__c)so;
            if(!processedaccounts.contains(quoteid)){
                QuoteProposalId.add(quoteid);
                lstQuoteProposal.add(objQuote);
            }
        }
        if(QuoteProposalId.size()>0){
            log('Number of accounts to be processed: ' + QuoteProposalId.size());
            log('Account Ids: '+ QuoteProposalId);
            List<String> CCAddress=new List<String>();
            CCAddress.add('abaranwal@kloudrac.com');
            string TemplateId=system.Label.quoteEmailTemplate;
            
            processedaccounts.addAll(QuoteProposalId);
            try{
                Messaging.SingleEmailMessage[] mails=new Messaging.SingleEmailMessage[0];
                 
                for(Apttus_Proposal__Proposal__c qt:lstQuoteProposal){
                    list<string> AdditionalRecipients=new list<string>();
                    AdditionalRecipients.add(qt.Pending_With_Email__c);
                    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
                    mail.setToAddresses(AdditionalRecipients);
                    mail.setCcAddresses(CCAddress);
                    //mail.setOrgWideEmailAddressId(OrgWideEmailId);
                    mail.setTemplateId(TemplateId);
                    mail.whatid=qt.id;
                    mail.setTargetObjectId('003n0000008FULE'); 
                    mails.add(mail);

                }
                
                log('Sending emails ... count: ' + mails);
                Messaging.sendEmail(mails); 
            
                        
            }catch(Exception e) {
                haserror=true;
                string body=e.getMessage();
                log(body);
    
            }
        }else{
            log('No Quote/Proposal is processed in this batch');
        }
        ++batchcounter;
    }

    global void finish(Database.BatchableContext BC){
        log('Entire batch process has ended');
        SaveDebugLog();
    } 
    
    public static void SendEmail(String Subject,String Body,String[] Recipeints){
        /*String Displayname=Lookup.getTarget('UpdateOpportunity', 'Config','FromAddress', true);
        //OneCRM.sandbox@ge.com
        Id OrgWideEmailId=[Select Id, DisplayName, Address from OrgWideEmailAddress where Address =:Displayname].Id;    
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        mail.setToAddresses(Recipeints);
        mail.setSubject(Subject);
        mail.setPlainTextBody(Body);
        mail.setOrgWideEmailAddressId(OrgWideEmailId);
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail});*/
                
    }
    

    private void log(string msg){
        debuglog+=msg+'\n';
        system.debug(logginglevel.info,msg);
    }
    
    private Id SaveDebugLog(){
        String recStr =  'Transaction Log';
        
        Integration_Log__c log= new Integration_Log__c();
        log.Call_Method__c = 'BatchProcessQuoteProposalEscalationEmail';
        log.Object_Name__c = 'Quote/Proposal';
        log.Call_Time__c = processstarttime;            
        log.Status__c = haserror?'Failure':'Success';
        insert log;        
        
        recStr += '\nInterfaceId:' + log.Object_Name__c;
        recStr += '\nObjectId:' + log.Object_Id__c;
        recStr += '\nCallTime:' + log.Call_Time__c.format('yyyy.MM.dd  HH:mm:ss.SSS z');
        recStr += '\nStatus:' + log.Status__c;
        recStr += '\nLogId:'+ log.Id;
        recStr += '\n';            
        recStr += debuglog;
        
        Blob recBlob= Blob.valueOf(recStr);
        Attachment att= new attachment();
        att.Name = 'Log Details ' +system.now()+'.txt';
        att.ParentId = log.Id; 
        att.Body = Blob.valueof(recStr); 
        insert att;     
        
        return log.id;
    }    
    
    public static void startbatch(datetime activitytime){
        
        EmailAlertToQuoteProposalApprovalUser aula=new EmailAlertToQuoteProposalApprovalUser(activitytime);
        aula.log('activitytime: ' + activitytime);
        aula.EndTime=activitytime;
        if(activitytime==null){
            aula.EndTime=System.now().adddays(-1);
        }
        ID batchprocessid = Database.executeBatch(aula);
        System.debug('Apex Job id: ' + batchprocessid );
    }
}


And here is schedulable:  I want to run batch file after every 5 minutes... Please Help
===============================================

global class scheduledQuoteReminderBatchable implements Schedulable {
   global void execute(SchedulableContext sc) {
       EmailAlertToQuoteProposalApprovalUser aula=new EmailAlertToQuoteProposalApprovalUser(system.now());
       ID batchprocessid = Database.executeBatch(aula);
       
   }
}
Ketankumar PatelKetankumar Patel
By default you can run apex job every 1 hour using cron expression but you can schedule this job 12 times at 5 min duration. However only 100 Apex classes can be scheduled concurrently and 5 batch Apex jobs can be queued or active concurrently.

http://resources.docs.salesforce.com/198/10/en-us/sfdc/pdf/salesforce_app_limits_cheatsheet.pdf
 
String sch1 = '0 0 * * * ?';
scheduledQuoteReminderBatchable sqrb1 = new scheduledQuoteReminderBatchable();
system.schedule('Every Hour plus 0 min', sch1, sqrb1);

String sch2 = '0 5 * * * ?';
scheduledQuoteReminderBatchable sqrb2 = new scheduledQuoteReminderBatchable();
system.schedule('Every Hour plus 5 min', sch2, sqrb2);

String sch2 = '0 10 * * * ?';
scheduledQuoteReminderBatchable sqrb2 = new scheduledQuoteReminderBatchable();
system.schedule('Every Hour plus 10 min', sch1, sqrb2);

String sch3 = '0 15 * * * ?';
scheduledQuoteReminderBatchable sqrb3 = new scheduledQuoteReminderBatchable();
system.schedule('Every Hour plus 15 min', sch3, sqrb3);
.
.
.
.
//You get the idea.
.
.
.
.
String sch12 = '0 55 * * * ?';
scheduledQuoteReminderBatchable sqrb12 = new scheduledQuoteReminderBatchable();
system.schedule('Every Hour plus 55 min', sch12, sqrb12 );
James LoghryJames Loghry
Currently, you're limited to running a batch class every hour via the Salesforce UI.  However, you can use Apex or Execute Anonymous from the dev console / mavensmate to kick off a batch class in smaller intervals than that.  You do this by using a cron syntax, as shown in this SSE post: http://salesforce.stackexchange.com/questions/37333/how-to-run-a-scheduled-job-every-15-minutes

Beware though, as batch classes hardly ever kick off on time.  That is, they kick off whenever the resources are available after they are supposed to start.  I've gone down the "run batch apex every 5 minute" road before, and the batch jobs typically overlap pretty quickly.  In other words, I would consider spacing your batch jobs out to at least 15 minutes.
James LoghryJames Loghry
Also, if you want that minute of a timeframe, you might have to create multiple schedules of the same batch job.  For instance, one batch kicks off at 0:15 of the hour, the second is scheduled for 0:30, third is scheduled for 0:45, fourth is scheduled for 00:00.
Radhe ShyamRadhe Shyam
Thanks@Ketankumar Patel,
I am new in this apex batch and all,

please help me out to write the proper code: How to insert your code in this below code.....or we need to write some othe class file?

global class scheduledQuoteReminderBatchable implements Schedulable {
   global void execute(SchedulableContext sc) {
       EmailAlertToQuoteProposalApprovalUser aula=new EmailAlertToQuoteProposalApprovalUser(system.now());
       ID batchprocessid = Database.executeBatch(aula);
       
   }
}

 
Ketankumar PatelKetankumar Patel
Hi Radhe,

You don't need to insert my code into your code. If you have valid scheduable class then you need to run each block of below code in developer console. That will schedule your batch class.
String sch1 = '0 0 * * * ?';
scheduledQuoteReminderBatchable sqrb1 = new scheduledQuoteReminderBatchable();
system.schedule('Every Hour plus 0 min', sch1, sqrb1);
Radhe ShyamRadhe Shyam
But i need to write it once some where, the class should be get execute after every 5 minuts. is it possible?
Nitish TalekarNitish Talekar
To run Schedule a Class In Every 5 Mins in Salesforce,
Check this out: http://howtodoitinsalesforce.blogspot.in/2016/12/run-schedule-class-in-every-5-mins-in.html
Christina ZhankoChristina Zhanko
Hi, Radhe! I had a similar problem.
Try to use Schedule Helper. Allows you to manage your schedules to execute even every 5 minutes.
From AppExchange - https://appexchange.salesforce.com/listingDetail?listingId=a0N3A00000DqCmYUAV
docbilldocbill
It is 2018, and still the same problem.  We did the really stupid thing 6 years ago, which is I wrote one scheduled job that will invoke all our our batch jobs based on custom settings, and scheduled that custom job for every minute of every day.   It actually works well, but the problem is that left us just 40 job slots for managed packages.   Now we are about 20 short of what we need...

I was looking for something a bit more clever than the self rescheduling trick.   The problem with that is when salesforce gets busy, that can turn a once in every 1 minute schedule to a once every 5 minute schedule...  So far no simple solutions, just complex ones.

This wouldn't be such an issue if salesforce would implement the ability to schedule more than once an hour, or if they were to make managed packages use their own schedule queue, rather than sharing same queue with unmanaged applications.
 
Jatin NarulaJatin Narula
Hello Everyone,

You can use this logic to achieve it:

Integer frequency = 15;    // interval in minutes you want apex to schedule ie. 2, 3, 5, 10, 15
Integer totalIterations = 60/frequency - 1;

for(Integer i = 0; i <= totalIterations; i++){
    Integer count = i*frequency;
    String minuteString = (count < 10) ? '0' + count : '' + count;
    System.schedule('Scheduled Job ' + i,  '0 ' + minuteString + ' * * * ?', new ApexScheduler());  //  ApexScheduler is a class that implements schedulable interface 
}

Let me know if you have any questions.


Best,
Jatin Narula
 
Ashwin KhedekarAshwin Khedekar
You can make an Apex scheduler class to reschedule its n number of future runs through the code in the class which implements the Schedulable interface. Suppose you want to reschedule 20 runs at gap of 5 minutes each, then just change "count" in below code in the while loop :- while(count < 5) change to while(count < 20) :-

// The scheduler class :-
global without sharing class SchedulerClass2 implements Schedulable
{
    Integer count = 0;
    Integer gapMinutes = 5;
        
    public void execute(SchedulableContext sc) {
    
        System.debug(LoggingLevel.INFO, '#### execute method starts of SchedulerClass2');

        // Re-schedule only once if "Check x min trigger" field does not have
        // value "WorkerClass" in it. This is a custom field of type text on Account object.
        // API name of this field is :- 
        Account a = [Select id, name, Check_x_min_trigger__c from Account where name = 'ListAcc10000'];
        // Create an account with name = 'ListAcc10000'. Keep its field "Check x min trigger" empty.

        System.debug(LoggingLevel.INFO, '#### queried account is ' + a);
        System.debug(LoggingLevel.INFO, '#### queried account Check_x_min_trigger__c is ' + a.Check_x_min_trigger__c);
        
        // When the batch class code runs, it will populate the value "WorkerClass" in the field "Check x min trigger"
        // of all the accounts in the database
        if(a.Check_x_min_trigger__c != 'WorkerClass')
        {
            System.debug(LoggingLevel.INFO, '#### rescheduling SchedulerClass2');
            // Re-schedule ourself 5 times to run again at gap of 5 minutes
            while(count < 5) {
                DateTime now  = DateTime.now();
                DateTime nextRunTime = now.addMinutes(gapMinutes);
                System.debug(LoggingLevel.INFO, '#### nextRunTime is ' + nextRunTime);
                
                String cronString = '' + nextRunTime.second() + ' ' + nextRunTime.minute() + ' ' + 
                    nextRunTime.hour() + ' ' + nextRunTime.day() + ' ' + 
                    nextRunTime.month() + ' ? ' + nextRunTime.year();
                // format for cronString is seconds minutes hours day_of_month month day_of_week year
                System.debug(LoggingLevel.INFO, '#### calculated cronString is ' + cronString);
        
                System.schedule(SchedulerClass2.class.getName() + '-' + nextRunTime.format(), cronString, new SchedulerClass2());
                count++;
                System.debug(LoggingLevel.INFO, '#### count incremented, new count is ' + count);
                gapMinutes = gapMinutes + 5; // add gap of 5 minutes for each future run.
                System.debug(LoggingLevel.INFO, '#### gapMinutes incremented, new gapMinutes is ' + gapMinutes);
            }
        }
        
        // Launch a batch job to do the actual work
        WorkerClass wc = new WorkerClass();
        System.debug(LoggingLevel.INFO, '#### about to call executeBatch of WorkerClass');
        Database.executeBatch(wc);
    }
}

// The batch class which will do the actual work. It will populate the value "WorkerClass" in the custom field
// "Check x min trigger" on all account records in the database.
global class WorkerClass implements Database.Batchable<SObject>
{
    global Database.QueryLocator start(Database.BatchableContext bc)
    {
        String query = 'Select id, name, City__c, Check_x_min_trigger__c from Account';
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, list<SObject> scope)
    {
        System.debug(LoggingLevel.INFO, '#### execute method of batch class starts in WorkerClass');
        List<Account> accLstToUpdate = new List<Account>();
        if(scope != null)
        {
            List<Account> accLst = (List<Account>)scope;
            for(Account a : accLst)
            {
                a.Check_x_min_trigger__c = 'WorkerClass';
                accLstToUpdate.add(a);
            }
            
            if(accLstToUpdate.size() > 0)
            {
                System.debug(LoggingLevel.INFO, '#### execute method of batch class: updating accLstToUpdate ' + accLstToUpdate.size());       
                update accLstToUpdate;
            }
        }
    }

    global void finish(Database.BatchableContext BC)
    {
        System.debug(LoggingLevel.INFO, '#### finish method of batch class');
    }
}

From Developer Console -> Execute Anonymous, call the scheduler class :-
SchedulerClass2 sc2 = new SchedulerClass2();
String stringTime = '0 55 * * * ?'; // will run at 55 minutes past every hour
String jobID = system.schedule('SchedulerClass2Scheduler', stringTime, sc2);

Go to Setup -> Jobs -> Scheduled Jobs to see the future run Apex Scheduler jobs queued up.
Coding-With-The-ForceCoding-With-The-Force
Hey there, I know this thread is a bit old, but I figured out a super good way to do this by having the scheduled class reschedule itself every 5 minutes. This way you only have one scheduled job that re-schedules itself every five minutes.

There's a video walkthrough here and there's links to my github code example in the video's description: https://youtu.be/NjY51eURQXc
amar sharma 7amar sharma 7
global class testScheduleClass  implements Schedulable {
 
    private final String JOBNAME = 'Repeating Job';
    private final Integer FIVEMINUTE =5;

    public void execute(SchedulableContext cont)
    {    System.debug('every 5 min');
        findAndAbortJob(cont);
    }

    private void findAndAbortJob(SchedulableContext cont)
    {
        if (cont == null)
        {
            return;
        }
        
        List<CronJobDetail> cronDetail = [SELECT Id FROM CronJobDetail WHERE Name= :JOBNAME LIMIT 1];

        if (cronDetail.isEmpty())
        {
            return;
        }

        
        List<CronTrigger> cronTriggers = [SELECT Id FROM CronTrigger WHERE CronJobDetailId = :cronDetail[0].Id];

        if(cronTriggers.isEmpty())
        {
            return;
        }

        try
        {
        
            System.abortJob(cronTriggers[0].Id);
            rescheduleJob();
        }
        catch (Exception e)
        {
            System.debug('This was the error ::: ' + e.getMessage());
        }
    }
    public  void rescheduleJob()
    {
        Datetime sysTime = System.now().addMinutes(FIVEMINUTE);
        String cronExpression = '' + sysTime.second() + ' ' + sysTime.minute() + ' ' + sysTime.hour() + ' ' + sysTime.day() + ' ' + sysTime.month() + ' ? ' + sysTime.year();
        System.schedule(JOBNAME, cronExpression, new testScheduleClass());
    }    
}

 
Rishabh Mathur 11Rishabh Mathur 11
Thank you Amar Sharma, this code works for me.