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
Irvine DelacroixIrvine Delacroix 

system.limitexception too many future calls 51 How to get around this?

Hello, I am receiving the Error "system.limitexception too many future calls 51" when I Inserted 300+ records in our Org. I would like an assistance to get around this Error. I hope someone can help here.. I am new to Apex Code for Callouts.. Here's my code.


TRIGGER:

trigger SG_ContactTriggers on Contact (after insert) {

    //TriggerHandler
    TriggerHandlerREST handler = new TriggerHandlerREST();
    
    if(trigger.isAfter){
        handler.UPDATE_CONTACT_ADDRESS(trigger.new);
    }
}


And Here's my CLASS​

public class TriggerHandlerREST {
    //GET GEOCODE METHOD
    public void UPDATE_CONTACT_ADDRESS(List<contact> newContacts){
        
        List<contact> contactsToUpdate = new List<contact>();
        for(contact contacts : [select id, MailingPostalCode from contact where id in: newContacts]){
            
        	GET_GEOCODE(contacts.MailingPostalCode,contacts.id);
        
        }
    }
    
    @future(callout=true)
    public static void GET_GEOCODE(String POSTAL_CODE,string contactID){
        
        contact con = [select id,MailingCity,MailingState,MailingCountry from contact where id =:contactId];
        
        
        String ENDPOINT = 'https://maps.google.com/maps/api/geocode/json?key=AIzaSyAGXR9Ybwo_YxMQvyb-XRP_36fT5_wkeFU&components=country:AU|postal_code:'+POSTAL_CODE+'&sensor=false';
            try{
                HTTPRequest request = new HTTPRequest();
                request.setEndpoint(ENDPOINT);
                request.setHeader('Content-Type', 'application/json');
                request.setMethod('GET');
                
                HTTP http = new HTTP();
                HTTPResponse  response =  http.send(request);
                
                GeoCodeResult geo =(GeoCodeResult)JSON.deserialize(response.getBody(),GeoCodeResult.class);
                
                if(geo.status == 'OK'){
                for(Results results : geo.results){
                    for( Address_components address : results.address_Components){
                        if(address.types.get(0)=='locality'){con.MailingCity=address.long_name;}else if(address.types.get(0)=='administrative_area_level_1'){con.MailingState=address.long_name;}else if(address.types.get(0)=='country'){ con.MailingCountry=address.long_name; }
                    }
                }
                    update con; //UPDATE THE CONTACT
                    
                } else { system.debug('@NUR results === '+geo.status);}
   				
            }catch(Exception e){
               String errorMessage='';
               errorMessage=e.getMessage();
               errorMessage+= ' ::: inside updateAddressByGeocode.getUserByEmail(string email)  ....';
            }
    }
    
    /////HELPER CLASS
    public class GeoCodeResult {
        public List<Results> results;
        public String status;

    }
    
    public class Address_components {
        public String long_name;
        public String short_name;
        public List<String> types;
    }
    
    public class Results {
        public List<Address_components> address_components;
    }
}


Thank you so much in Advance!
Best Answer chosen by Irvine Delacroix
Irvine DelacroixIrvine Delacroix

Thank you for the Response.

I have Updated my Class so it will be bulkified. Please correct my code if there's any mistake you see. I would like to call this from trigger. Please let me know how.

 

global class TriggerHandlerRESTBatch implements database.Batchable<sObject>,Database.AllowsCallouts,database.stateful{
    
    public List<contact> contactIds;
    public list<contact> contactsToUpdate = new list<contact>();
    
    //QUERY
    global Database.querylocator start(Database.BatchableContext BC){
        string query = 'select id,MailingCity,MailingState,MailingCountry,MailingPostalCode from contact where id in:ContactIds';
        return Database.getQueryLocator(query);
    }
	    
    global void execute(Database.BatchableContext BC, List<sObject> scope){
        
        List<contact> Contacts = (List<contact>)scope;
        for(contact con : Contacts){
            //ENDPOINT
            String ENDPOINT = 'https://maps.google.com/maps/api/geocode/json?key=AIzaSyAGXR9Ybwo_YxMQvyb-XRP_36fT5_wkeFU&components=country:AU|postal_code:'+con.MailingPostalCode+'&sensor=false';
            
            HTTPRequest request = new HTTPRequest();
            request.setEndpoint(ENDPOINT);
            request.setHeader('Content-Type', 'application/json');
            request.setMethod('GET');
            
            HTTP http = new HTTP();
            HTTPResponse  response =  http.send(request);
            
            GeoCodeResult geo =(GeoCodeResult)JSON.deserialize(response.getBody(),GeoCodeResult.class);
            
            if(geo.status == 'OK'){
                    for(Results results : geo.results){
                        for( Address_components address : results.address_Components){
                            if(address.types.get(0)=='locality'){con.MailingCity=address.long_name;}else if(address.types.get(0)=='administrative_area_level_1'){con.MailingState=address.long_name;}else if(address.types.get(0)=='country'){ con.MailingCountry=address.long_name; }
                        }
                    }
                    
            } else {
                system.debug('@NUR results === '+geo.status);
            }
            
            //ADD CONTACTS TO UPDATE TO THE LIST
            contactsToUpdate.add(con);
        }
        
    }
    
    //FINISH METHOD
    global void finish(Database.BatchableContext BC){
        Try{
            update contactsToUpdate;
        }
        catch (exception ex){
            System.debug(ex);
        }
    }
    /////HELPER CLASS
    public class GeoCodeResult {
        public List<Results> results;
        public String status;

    }
    
    public class Address_components {
        public String long_name;
        public String short_name;
        public List<String> types;
    }
    
    public class Results {
        public List<Address_components> address_components;
    }
}


Thank you!

All Answers

Prakash NawalePrakash Nawale
In order to void this error you need to checks how many call you executed 
use limit class
system.Limits.getFutureCalls()
                Returns the number of methods with the future annotation that have been executed (not necessarily completed).
system.Limits.getLimitFutureCalls()
            Returns the total number of methods with the future annotation that can be executed (not necessarily completed).

FYI : https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_limits.htm
 
Rohit Goyal 5Rohit Goyal 5
If you need to bulkify this thing then instead of using a future method. You can go for batch implementing Iterable interface. Using this you will have sufficient limit to invoke any API for the incoming records in a Trigger. To know more about Iterable interface with Batch apex, visit here.
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm
Irvine DelacroixIrvine Delacroix

Thank you for the Response.

I have Updated my Class so it will be bulkified. Please correct my code if there's any mistake you see. I would like to call this from trigger. Please let me know how.

 

global class TriggerHandlerRESTBatch implements database.Batchable<sObject>,Database.AllowsCallouts,database.stateful{
    
    public List<contact> contactIds;
    public list<contact> contactsToUpdate = new list<contact>();
    
    //QUERY
    global Database.querylocator start(Database.BatchableContext BC){
        string query = 'select id,MailingCity,MailingState,MailingCountry,MailingPostalCode from contact where id in:ContactIds';
        return Database.getQueryLocator(query);
    }
	    
    global void execute(Database.BatchableContext BC, List<sObject> scope){
        
        List<contact> Contacts = (List<contact>)scope;
        for(contact con : Contacts){
            //ENDPOINT
            String ENDPOINT = 'https://maps.google.com/maps/api/geocode/json?key=AIzaSyAGXR9Ybwo_YxMQvyb-XRP_36fT5_wkeFU&components=country:AU|postal_code:'+con.MailingPostalCode+'&sensor=false';
            
            HTTPRequest request = new HTTPRequest();
            request.setEndpoint(ENDPOINT);
            request.setHeader('Content-Type', 'application/json');
            request.setMethod('GET');
            
            HTTP http = new HTTP();
            HTTPResponse  response =  http.send(request);
            
            GeoCodeResult geo =(GeoCodeResult)JSON.deserialize(response.getBody(),GeoCodeResult.class);
            
            if(geo.status == 'OK'){
                    for(Results results : geo.results){
                        for( Address_components address : results.address_Components){
                            if(address.types.get(0)=='locality'){con.MailingCity=address.long_name;}else if(address.types.get(0)=='administrative_area_level_1'){con.MailingState=address.long_name;}else if(address.types.get(0)=='country'){ con.MailingCountry=address.long_name; }
                        }
                    }
                    
            } else {
                system.debug('@NUR results === '+geo.status);
            }
            
            //ADD CONTACTS TO UPDATE TO THE LIST
            contactsToUpdate.add(con);
        }
        
    }
    
    //FINISH METHOD
    global void finish(Database.BatchableContext BC){
        Try{
            update contactsToUpdate;
        }
        catch (exception ex){
            System.debug(ex);
        }
    }
    /////HELPER CLASS
    public class GeoCodeResult {
        public List<Results> results;
        public String status;

    }
    
    public class Address_components {
        public String long_name;
        public String short_name;
        public List<String> types;
    }
    
    public class Results {
        public List<Address_components> address_components;
    }
}


Thank you!
This was selected as the best answer
Irvine DelacroixIrvine Delacroix

Actually, It's all good. I have this Code and it's now working as expected. Thank you very much for all the Help! :)

 

if(trigger.isAfter && Trigger.isInsert){
        //handler.UPDATE_CONTACT_ADDRESS(trigger.new,null,false);
        set<id> contactIds = new set<id>();
        for(contact con : trigger.new){contactIds.add(con.id);}
        handler.contactids=contactIds;
        ID batchprocessid = Database.executeBatch(handler,200);
    }