Apex Scheduler

To invoke Apex classes to run at specific times, first implement the Schedulable interface for the class, then specify the schedule using either the Schedule Apex page in the Salesforce user interface, or the System.schedule method.

Important
Salesforce schedules the class for execution at the specified time. Actual execution may be delayed based on service availability.

You can only have 100 scheduled Apex jobs at one time. You can evaluate your current count by viewing the Scheduled Jobs page in Salesforce and creating a custom view with a type filter equal to “Scheduled Apex”. Note that you can also programmatically query the CronTrigger object to get the count of scheduled jobs, but this count includes all scheduled job types, not only Apex scheduled jobs.

Use extreme care if you’re planning to schedule a class from a trigger. You must be able to guarantee that the trigger won’t add more scheduled classes than the 100 that are allowed. In particular, consider API bulk updates, import wizards, mass record changes through the user interface, and all cases where more than one record can be updated at a time. Note that the 100 concurrent scheduled classes limit doesn’t apply to scheduled batch jobs started using the System.scheduleBatch method.

You cannot update an Apex class if there are one or more active scheduled jobs for that class.

Implementing the Schedulable Interface

To schedule an Apex class to run at regular intervals, first write an Apex class that implements the Salesforce-provided interface Schedulable.

The scheduler runs as system—all classes are executed, whether or not the user has permission to execute the class.

To monitor or stop the execution of a scheduled Apex job using the Salesforce user interface, from Setup, click Monitoring | Scheduled Jobs or Jobs | Apex Jobs.

The Schedulable interface contains one method that must be implemented, execute.
global void execute(SchedulableContext sc){}

The implemented method must be declared as global or public.

Use this method to instantiate the class you want to schedule.
Tip
Though it's possible to do additional processing in the execute method, we recommend that all processing take place in a separate class.

The following example implements the Schedulable interface for a class called mergeNumbers:

global class scheduledMerge implements Schedulable{
   global void execute(SchedulableContext SC) {
      mergeNumbers M = new mergeNumbers(); 
   }
}

The following example uses the System.Schedule method to implement the above class.

scheduledMerge m = new scheduledMerge();
        String sch = '20 30 8 10 2 ?';
        system.schedule('Merge Job', sch, m);

You can also use the Schedulable interface with batch Apex classes. The following example implements the Schedulable interface for a batch Apex class called batchable:

global class scheduledBatchable implements Schedulable{
   global void execute(SchedulableContext sc) {
      batchable b = new batchable(); 
      database.executebatch(b);
   }
}

Use the SchedulableContext object to keep track of the scheduled job once it's scheduled. The SchedulableContext method getTriggerID returns the ID of the CronTrigger object associated with this scheduled job as a string. Use this method to track the progress of the scheduled job.

To stop execution of a job that was scheduled, use the System.abortJob method with the ID returned by the.getTriggerID method.

Testing the Apex Scheduler

The following is an example of how to test using the Apex scheduler.

The System.schedule method starts an asynchronous process. This means that when you test scheduled Apex, you must ensure that the scheduled job is finished before testing against the results. Use the Test methods startTest and stopTest around the System.schedule method to ensure it finishes before continuing your test. All asynchronous calls made after the startTest method are collected by the system. When stopTest is executed, all asynchronous processes are run synchronously. If you don’t include the System.schedule method within the startTest and stopTest methods, the scheduled job executes at the end of your test method for Apex saved using Salesforce.com API version 25.0 and later, but not in earlier versions.

This is the class to be tested.
global class TestScheduledApexFromTestMethod implements Schedulable {

// This test runs a scheduled job at midnight Sept. 3rd. 2022

   public static String CRON_EXP = '0 0 0 3 9 ? 2022'; global void execute(SchedulableContext ctx) { CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime FROM CronTrigger WHERE Id = :ctx.getTriggerId()]; System.assertEquals(CRON_EXP, ct.CronExpression); System.assertEquals(0, ct.TimesTriggered); System.assertEquals('2022-09-03 00:00:00', String.valueOf(ct.NextFireTime)); Account a = [SELECT Id, Name FROM Account WHERE Name = 'testScheduledApexFromTestMethod']; a.name = 'testScheduledApexFromTestMethodUpdated'; update a; } }
The following tests the above class:
@istest

class TestClass {

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

      Account a = new Account();
      a.Name = 'testScheduledApexFromTestMethod';
      insert a;

   // Schedule the test job

      String jobId = System.schedule('testBasicScheduledApex',
      TestScheduledApexFromTestMethod.CRON_EXP, 
         new TestScheduledApexFromTestMethod());
   // Get the information from the CronTrigger API object

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

   // Verify the expressions are the same
      System.assertEquals(TestScheduledApexFromTestMethod.CRON_EXP, 
         ct.CronExpression);

   // Verify the job has not run
      System.assertEquals(0, ct.TimesTriggered);

   // Verify the next time the job will run
      System.assertEquals('2022-09-03 00:00:00', 
         String.valueOf(ct.NextFireTime));
      System.assertNotEquals('testScheduledApexFromTestMethodUpdated',
         [SELECT id, name FROM account WHERE id = :a.id].name);

   Test.stopTest();

   System.assertEquals('testScheduledApexFromTestMethodUpdated',
   [SELECT Id, Name FROM Account WHERE Id = :a.Id].Name);

   }
}

Using the System.Schedule Method

After you implement a class with the Schedulable interface, use the System.Schedule method to execute it. The scheduler runs as system—all classes are executed, whether or not the user has permission to execute the class.
Note
Use extreme care if you’re planning to schedule a class from a trigger. You must be able to guarantee that the trigger won’t add more scheduled classes than the 100 that are allowed. In particular, consider API bulk updates, import wizards, mass record changes through the user interface, and all cases where more than one record can be updated at a time. Note that the 100 concurrent scheduled classes limit doesn’t apply to scheduled batch jobs started using the System.scheduleBatch method.
The System.Schedule method takes three arguments: a name for the job, an expression used to represent the time and date the job is scheduled to run, and the name of the class. This expression has the following syntax:
Seconds Minutes Hours Day_of_month Month Day_of_week optional_year
Note
Salesforce schedules the class for execution at the specified time. Actual execution may be delayed based on service availability.

The System.Schedule method uses the user's timezone for the basis of all schedules.

The following are the values for the expression:

Name Values Special Characters
Seconds 0–59 None
Minutes 0–59 None
Hours 0–23 , - * /
Day_of_month 1–31 , - * ? / L W
Month 1–12 or the following:
  • JAN
  • FEB
  • MAR
  • APR
  • MAY
  • JUN
  • JUL
  • AUG
  • SEP
  • OCT
  • NOV
  • DEC
, - * /
Day_of_week 1–7 or the following:
  • SUN
  • MON
  • TUE
  • WED
  • THU
  • FRI
  • SAT
, - * ? / L #
optional_year null or 1970–2099 , - * /
The special characters are defined as follows:
Special CharacterDescription
,Delimits values. For example, use JAN, MAR, APR to specify more than one month.
-Specifies a range. For example, use JAN-MAR to specify more than one month.
*Specifies all values. For example, if Month is specified as *, the job is scheduled for every month.
?Specifies no specific value. This is only available for Day_of_month and Day_of_week, and is generally used when specifying a value for one and not the other.
/ Specifies increments. The number before the slash specifies when the intervals will begin, and the number after the slash is the interval amount. For example, if you specify 1/5 for Day_of_month, the Apex class runs every fifth day of the month, starting on the first of the month.
L Specifies the end of a range (last). This is only available for Day_of_month and Day_of_week. When used with Day of month, L always means the last day of the month, such as January 31, February 28 for leap years, and so on. When used with Day_of_week by itself, it always means 7 or SAT. When used with a Day_of_week value, it means the last of that type of day in the month. For example, if you specify 2L, you are specifying the last Monday of the month. Do not use a range of values with L as the results might be unexpected.
W Specifies the nearest weekday (Monday-Friday) of the given day. This is only available for Day_of_month. For example, if you specify 20W, and the 20th is a Saturday, the class runs on the 19th. If you specify 1W, and the first is a Saturday, the class does not run in the previous month, but on the third, which is the following Monday.
Tip
Use the L and W together to specify the last weekday of the month.
# Specifies the nth day of the month, in the format weekday#day_of_month. This is only available for Day_of_week. The number before the # specifies weekday (SUN-SAT). The number after the # specifies the day of the month. For example, specifying 2#2 means the class runs on the second Monday of every month.

The following are some examples of how to use the expression.

Expression Description
0 0 13 * * ? Class runs every day at 1 PM.
0 0 22 ? * 6L Class runs the last Friday of every month at 10 PM.
0 0 10 ? * MON-FRI Class runs Monday through Friday at 10 AM.
0 0 20 * * ? 2010 Class runs every day at 8 PM during the year 2010.

In the following example, the class proschedule implements the Schedulable interface. The class is scheduled to run at 8 AM, on the 13th of February.

proschedule p = new proschedule();
        String sch = '0 0 8 13 2 ?';
        system.schedule('One Time Pro', sch, p);

Using the System.scheduleBatch Method for Batch Jobs

You can call the System.scheduleBatch method to schedule a batch job to run once at a specified time in the future. This method is available only for batch classes and doesn’t require the implementation of the Schedulable interface. This makes it easy to schedule a batch job for one execution. For more details on how to use the System.scheduleBatch method, see Using the System.scheduleBatch Method.

Apex Scheduler Limits

Apex Scheduler Best Practices

  • Salesforce schedules the class for execution at the specified time. Actual execution may be delayed based on service availability.
  • Use extreme care if you’re planning to schedule a class from a trigger. You must be able to guarantee that the trigger won’t add more scheduled classes than the 100 that are allowed. In particular, consider API bulk updates, import wizards, mass record changes through the user interface, and all cases where more than one record can be updated at a time. Note that the 100 concurrent scheduled classes limit doesn’t apply to scheduled batch jobs started using the System.scheduleBatch method.
  • Though it's possible to do additional processing in the execute method, we recommend that all processing take place in a separate class.
  • You can't use the getContent and getContentAsPDFPageReference methods in scheduled Apex.
  • Synchronous Web service callouts are not supported from scheduled Apex. To be able to make callouts, make an asynchronous callout by placing the callout in a method annotated with @future(callout=true) and call this method from scheduled Apex. However, if your scheduled Apex executes a batch job, callouts are supported from the batch class. See Using Batch Apex.
© Copyright 2000–2013 salesforce.com, inc. All rights reserved.
Various trademarks held by their respective owners.