[SalesForce] Can a class implementing Database.Batchable also implement Schedulable and schedule itself to run

Rather than creating a separate Schedulable class which executes my Batchable class (which in turn has a callout), shouldn't I be able to have my Batchable class also implement the Schedulable interface and in the execute(SchedulableContext) method, new up the same Batchable class and pass it to the Database.executeBatch method?

This works fine when I execute the schedule from the dev console like so:

Batch_APNEmail batchApex = new Batch_APNEmail();
batchApex.execute(null);

But when I create a scheduled job through the Salesforce web interface and configure it to execute daily at 9am, it throws the exception:

System.CalloutException: Callout from scheduled Apex not supported.

My schedulable/batchable class declaration looks like this:

global class Batch_APNEmail implements Database.Batchable<sObject>, Database.Stateful, Database.AllowsCallouts, Schedulable

My Scheduleable execute method within the schedulable/batchable class looks like this:

global void execute(SchedulableContext sc){
    Batch_APNEmail batchAPN = new Batch_APNEmail();
    Database.executeBatch(batchAPN, 1);
}

Here's a unit test which runs successfully:

@isTest static void test_Schedule(){
    Create_APNs();

    // Setup the mock callouts with static resources
    Setup_Static_Resources();

    Test.startTest();
        Batch_APNEmail batchApex = new Batch_APNEmail();
        batchApex.execute(null);
    Test.stopTest();

    // Verify the callouts were made
    List<Academic_Progress_Notification__c> apns = [SELECT Emailed_Student__c FROM Academic_Progress_Notification__c];
    for (Academic_Progress_Notification__c apn : apns){
        System.assertEquals(apn.Emailed_Student__c != null, true);
    }

Best Answer

Yes. In general, you can combine as many interfaces as you want within a single class, so long as they are all compatible. Using the scheduable and batchable interface within the same class just means you have to implement all four methods. Your class will start off like:

public class x implements Database.Batchable<Object>, Database.AllowCallouts, Scheduable {

As an aside, you could also use Scheduable to call a future method, which may be simpler if you need just one callout (or, less than the 10 limit). In which case:

@future(callout=true) public static void doCallout() {
Related Topic