I need to create a schedulable Apex job which will send Sales Order Number from Case Object to my integration platform Web Service as JSON. This will be re-mapped and sent to another system, re-mapped again and send to be received by REST HTTP PATCH back in Salesforce.

I never worked in APEX and never had much experience before so I struggle a bit. To schedule I use Apex Schedule rather than CRON_EXP. I don't have a clue why the code below doesn't execute as it supposed to.

global class calloutPOSTClass implements Schedulable{

global void execute (SchedulableContext ctx){
    List<Case> salesordernumber = [SELECT Sales_Order_Number__c 
                              FROM Case
                              WHERE Sales_Order_Number__c != null AND
                              Status = 'Approved'];

    //future callout method to post http request

@future (Callout=true)
    public static void getPickedShippedUpdate(String salesordernumber){

    Http http = new Http();
    HttpRequest req = new HttpRequest();

    req.setHeader('Content-Type', 'application/json');
    req.setBody('{"SONUMBER":"' + salesordernumber + '"}');

    HttpResponse response = http.send(req);   

Also, I struggle with creating test classes for @future callouts, if someone would be able to explain it or give me some tips I'd be very grateful.


  • Can you please provide debug logs for execution of your code? Also have you checked if you set up your endpoint https://myendpoint in the Remote Sites Settings? – Eduard Jul 25 '18 at 11:02
  • For your second question about testing @future methods with callouts, please explore this forum a bit more - you'll certainly find the answer - salesforce.stackexchange.com/… – Eduard Jul 25 '18 at 11:12

You have to explicitly call your future method with each sales order number found by your scheduler. Since your execute() method performs a query and then does no work, you're not going to see a result of it - the query contents are simply discarded.

There is a broader architectural issue, though. The limit for future method invocations in a transaction is 50:

Maximum number of methods with the future annotation allowed per Apex invocation : 50

This means that the moment your query returns more than 50 records, you'll be receiving limits exceptions.

Further, your class doesn't make any attempt to guard against reprocessing the same records, nor does it alter the record status when callouts are sent. If your class is scheduled on a tight timeline, you may process the same 50+ records repeatedly. I won't propose a solution to this because it's going to be quite specific to the callout/callback flow you're building here.

On the limits side, the very easy patch is to put a LIMIT 50 clause in your SOQL query. That means you'll process up to 50 records each time your scheduler goes off, and everything else will have to wait. If your throughput is >50 Cases per time interval of this class running, you'll never catch up. Probably not the way you want to go unless you're doing very little volume!

The better way to approach would be to build a schedulable Batch Apex class (you can implement both Schedulable and Batchable interfaces in the same class) and have your Schedulable execute() method create and enqueue a Batch Apex invocation. Your Batch Apex could run with a batch size of 50, to avoid the governor limit, and utilize the same query in its start() method.

Batch Apex will get you significantly higher throughput, and it's architecturally a sounder solution as you have more control over your limits consumption while maintaining performance.

For more, see Batch Apex.

If the intent is to do a more real-time process (not every N hours), a Queueable chain pattern may be something you want to look into.

| improve this answer | |
  • That's incredibly helpful! I didn't have a clue about the future methods restriction! From what I see the batch jobs will be a way to go. – Lukas Jul 25 '18 at 16:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.