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
Travis McDonaldTravis McDonald 

@future calls limit, how do I convert my trigger to be ran as a batch apex class to get around this?

Hey guys, so I have a trigger than runs whenever an address is updated or saved, to do reverse geocode and write the latitude and logitude to a field. The problem is, when a lot of records are updated at once, I run into the future call limit governer.....

See the code below: Any help is much appreciated.
 
/*// Trigger runs getLocation() on Accounts with no Geolocation

trigger SetGeolocation on Account (after insert, after update) {
    for (Account a : trigger.new)
    if (a.Location__Latitude__s == null)
          LocationCallouts.getLocation(a.id);
}*/

// Trigger runs getLocation() on Accounts with no Geolocation

trigger SetGeolocation on Account (after insert, after update) {
    for (Account a : trigger.new){
        if(system.isFuture() == FALSE){
          LocationCallouts.getLocation(a.id);
        }
    }
}

that's the trigger, which then runs this apex class:
 
public class LocationCallouts {

     @future (callout=true)  // future method needed to run callouts from Triggers
      static public void getLocation(id accountId){
        // gather account info
        Account a = [SELECT BillingCity,BillingCountry,BillingPostalCode,BillingState,BillingStreet FROM Account WHERE id =: accountId];

        // create an address string
        String address = '';
        if (a.BillingStreet != null)
            address += a.BillingStreet +', ';
        if (a.BillingCity != null)
            address += a.BillingCity +', ';
        if (a.BillingState != null)
            address += a.BillingState +' ';
        if (a.BillingPostalCode != null)
            address += a.BillingPostalCode +', ';
        if (a.BillingCountry != null)
            address += a.BillingCountry;

        address = EncodingUtil.urlEncode(address, 'UTF-8');

        // build callout
        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint('http://maps.googleapis.com/maps/api/geocode/json?address='+address+'&sensor=false');
        req.setMethod('GET');
        req.setTimeout(60000);

        try{
            // callout
            HttpResponse res = h.send(req);

            // parse coordinates from response
            JSONParser parser = JSON.createParser(res.getBody());
            double lat = null;
            double lon = null;
            while (parser.nextToken() != null) {
                if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) &&
                    (parser.getText() == 'location')){
                       parser.nextToken(); // object start
                       while (parser.nextToken() != JSONToken.END_OBJECT){
                           String txt = parser.getText();
                           parser.nextToken();
                           if (txt == 'lat')
                               lat = parser.getDoubleValue();
                           else if (txt == 'lng')
                               lon = parser.getDoubleValue();
                       }

                }
            }

            // update coordinates if we get back
            if (lat != null){
                a.Location__Latitude__s = lat;
                a.Location__Longitude__s = lon;
                update a;
            }

        } catch (Exception e) {
        }
    }
}

This works very well, until you try to update a lot of records at once....when you do you run into the @future calls limit.


I had read that using a batch apex class can solve this, any advice on how to do that is appreciated.

I had posted a previous thread where another developer suggested I use a list to get around this, and it seemed to work, but after testing it, it broke the writing of geocode to the location field. See this thread: https://developer.salesforce.com/forums/ForumsMain?id=906F0000000B2h8IAC



 
BalajiRanganathanBalajiRanganathan
You don't need to use Batch Apex for this Scenario. you should bulkify your future method

Instead of getLocation(id accountId), rewrite your future method to take list of Ids

getLocation(List<id> accountIds)

Check if your callout endpoint (Google API) can take multiple address in a single request.
else make sure that you pass max of 100 ids to your future methods.

below are the Governer limits you should consider.

Total number of callouts (HTTP requests or Web services calls) in a transaction 100
Maximum number of methods with the future annotation allowed per Apex invocation 50