4

I'm currently working with a customer that is interested in launching Salesforce Batch jobs from an external scheduler. I was thinking about the following

- Create a global interface 

    global interface TWSJob {
        void execute();
    }

- Create a RESTful web service

    @RestResource(urlMapping='/TWSSubmitApexClass/*')
    global with sharing class TWSSubmitApexClass{
        @HttpGet
        global static void doGet() {
            RestRequest req = RestContext.request;
            RestResponse res = RestContext.response;
            String apexClass = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
            Type t = Type.forName(apexClass);
            TWSJob s = (TWSJob)t.newInstance();
            s.execute();
        }
    }

- Create a RESTful web service (/TWSMonitorAPEXJob) to monitor the progress using AsyncApexJob.

What do you guys think?

Many thanks.

Miguel

1 Answer 1

3

You're not actually executing a batch. You're just running its execute function. This would limit your class to the normal REST API governor limits. Instead, you should a virtual class:

global virtual class BatchableObjectClass implements Database.Batchable<Object>, Database.Stateful {
    global virtual Iterable<Object> start(Database.BatchableContext bc) {
        return null;
    }
    global virtual void execute(Database.BatchableContext bc, Object[] items) {

    }
    global virtual void finish(Database.BatchableContext bc) {

    }
}

From here, your code has to change slightly to support this change:

@RestResource(urlMapping='/TWSSubmitApexClass/*')
global with sharing class TWSSubmitApexClass{
    @HttpGet
    global static void doGet() {
        RestRequest req = RestContext.request;
        RestResponse res = RestContext.response;
        String apexClass = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
        Type t = Type.forName(apexClass);
        Object s = t.newInstance();
        Database.executeBatch((Database.Batchable<Object>)s);
    }
}

This class handles normal "query type" projects and "iterable" type projects. The only downside is that your code will be required to cast generic objects and sobjects into concrete objects on the receiving end. This will only add a couple of lines of code, so it shouldn't be a big deal.

Note that for query types, you'll have to cast the query locator into an Iterable<Object> return type, and you'll have to cast the Object[] items into a SObject[] records variable to get at the SObject functions contained therein (you should also be able to cast directly to a known type, such as Account[], if you know the type beforehand).

Updates

  • Updated code to reflect a single virtual class instead of two-- the latter appears redundant.
5
  • Would you need two classes for Iterable vs SObject? Pretty sure you can use the Iterable one for both. Commented Oct 26, 2013 at 15:54
  • I actually tried a single class before I posted this code. If you try, you end up with two functions with a signature start(Database.batchableContext) (the return type doesn't factor into the signature), so you get a duplicate function error.
    – sfdcfox
    Commented Oct 26, 2013 at 16:00
  • I'm sure you only need the first/Iterable and that would work for QueryLocator too which I guess is also Iterable? Commented Oct 28, 2013 at 12:06
  • While all QueryLocators are Iterables, not all Iterables are QueryLocators. At least in previous incarnations of Apex Code, returning a normal Iterable resulted in the system calling next()/hasNext() repeatedly, resulting in a maximum number of records it could parse-- far less than the 50,000,000 that a true QueryLocator can access. If that's no longer true (or if I'm just hallucinating), then I see no reason why the first form won't necessary work (but then again, not all Objects are SObjects, either...
    – sfdcfox
    Commented Oct 28, 2013 at 12:53
  • It requires some extra casting, but you're right. It appears to work normally. You can therefore reduce the total solution down to just a single virtual class. I'm pretty sure this wouldn't have worked in an earlier version of Apex Code (I tried it once...), but it appears fully functional now.
    – sfdcfox
    Commented Oct 28, 2013 at 13:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .