function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
ekorzekorz 

Adapting an existing @future method HTTP callout for a monthly data sync

I realize there is a ton of material out there around bulk, batch, scheduled, @future apex, and that's actually my problem...  I'm not really sure what avenue to pursue.  For the sake of simplicity, this existing class updates the description field on Account using a @future HTTP callout (right from a great tutorial on cheenath.com):

 

public class AccountUpdater {

  //Future annotation to mark the method as async.
  @Future(callout=true)
  public static void updateAccount(String id, String name) {

    //construct an HTTP request
    HttpRequest req = new HttpRequest();
    req.setEndpoint('http://cheenath.com/tutorial/sfdc/sample1/data.txt');
    req.setMethod('GET');

    //send the request
    Http http = new Http();
    HttpResponse res = http.send(req);

    //check the response
    if (res.getStatusCode() == 200) {

      //update account
      Account acc = new Account(Id=id);
      acc.Description = res.getBody();
      update acc;
    } else {
      System.debug('Callout failed: ' + res);
    } 
  }
}

 

 

I have a trigger to fire that method after insert, and it works great.  My goal is to run the above @future method 'updateAccount', against all existing Accounts once per month (or a large subset determined by a query) Could you outline the archetecture of the system you'd use? 

 

I am fuzzy around how many classes I need to build (one to schedule, one to batch, one to execute, one to query?) and how they connect.  Can I reuse my existing @future method?  I get lost between batch apex, scheduled apex, how the limits hinder each avenue, etc. 

 

Thanks!

Best Answer chosen by Admin (Salesforce Developers) 
Starz26Starz26

You are limited to 10 callouts per batch apex.

 

A simple batch class would work setting the batch size to 10:

 

For example:

 

global class BatchAccountUpdate implements Database.Batchable<sObject>, Database.Stateful {
 
 
  global Database.QueryLocator start(Database.BatchableContext BC){
  
String query = 'Select ID, ....... From Account WHERE ......'; if(isTest) query += ' Limit 10'; return database.getQueryLocator(query); } global void execute(Database.BatchableContext BC, List<sObject> scope){ Account[] acc = (Account[])scope; for(Account a : acc){ //Do your callout here and update the account record accordingly } update acc; } global void finish(Database.BatchableContext BC){ } static testmethod void testBatchAccountUpdate(){ //set up your test records and you httpmock test.startTest(); BatchAccountUpdate batch = New BatchAccountUpdate(); database.executeBatch(batch, 10); test.stopTest(); } } Run your batch by calling BatchAccountUpdate b = New BatchAccountUpdate(); database.executeBatch(b,10);

 

All Answers

Starz26Starz26

You are limited to 10 callouts per batch apex.

 

A simple batch class would work setting the batch size to 10:

 

For example:

 

global class BatchAccountUpdate implements Database.Batchable<sObject>, Database.Stateful {
 
 
  global Database.QueryLocator start(Database.BatchableContext BC){
  
String query = 'Select ID, ....... From Account WHERE ......'; if(isTest) query += ' Limit 10'; return database.getQueryLocator(query); } global void execute(Database.BatchableContext BC, List<sObject> scope){ Account[] acc = (Account[])scope; for(Account a : acc){ //Do your callout here and update the account record accordingly } update acc; } global void finish(Database.BatchableContext BC){ } static testmethod void testBatchAccountUpdate(){ //set up your test records and you httpmock test.startTest(); BatchAccountUpdate batch = New BatchAccountUpdate(); database.executeBatch(batch, 10); test.stopTest(); } } Run your batch by calling BatchAccountUpdate b = New BatchAccountUpdate(); database.executeBatch(b,10);

 

This was selected as the best answer
Mayank_JoshiMayank_Joshi
Ok , if you have a trigger for making callouts then it will hit gover nor limit called (to many future callouts :11) . If trigger is processing more than 10 future methods / (records) in one contest .

Also, you can find my response here as well : http://boards.developerforce.com/t5/Apex-Code-Development/Getting-System-LimitException-Too-many-callouts-11/m-p/642331#M118871

To resolve this :
1: Restrict Trigger to make only 10 callouts
2: Or Create Batch Class that can call your Callout class . But ,keep in mind , batch class can not call future method ( batch/future class cannot call another future methos/class)
3: Need to create separate non future class and called it inside batch apex class .Again , Batch apex can not call more than one callout (governor limit) . Error stating: Too many callouts :10
4: To resolve, point 3 you need to set scope of batch from 200 (by dault) to 1 while execute /scheduliing your batch class

Note - we have to manually set Scope for batch, if there is need to set batch other than 200 . But , scope should only be in range of 1- 199 .

Eg . for executing batch apex code for Outbound callouts with scope defined as One .
Batch_closed_ca batchapex = new Batch_closed_ca();

// Defining scope for the batch ...
id batchprocessid = Database.executebatch(batchapex,1);
system.debug('Process_ID: ' + batchprocessid);
ekorzekorz

Thanks for the direction, both of you! 

 

I'm getting things to work by running one callout per batch, and all I had to do was add Database.AllowsCallouts to that global class and run:

 

BatchAccountUpdate b = New BatchAccountUpdate();
database.executeBatch(b,1);

 

Things look good from here, I think I can adapt this to be schedule-able, though I may just run it manually once per month since it's so easy.