Asynchronous calls with @Future

In this blog, I am going to how to make the asynchronous calls with @Future annotations .with the Future annotation you can make asynchronous Web service callout to an external service.A future method runs in the background, asynchronously. You can call a future method for executing long-running operations, such as callouts to external Web services or any operation you’d like to run in its own thread, on its own time.

What is Asynchronous Process in Salesforce 

An asynchronous process is a process or function which does not require interaction with a user. It can be used to execute a task “in the background” without the user having to wait for the task to finish. Force.com features such as Asynchronous Apex (@future), Batch Apex, Bulk API, Reports and other features use asynchronous processing to efficiently process requests.Each future method is queued and executes when system resources become available. That way, the execution of your code doesn’t have to wait for the completion of a long-running operation. A benefit of using future methods is that some governor limits are higher, such as SOQL query limits and heap size limits.

Use Case: – Upon Creation of Account Record, you need to validate the billing address of account and update latitude and longitude values.

Solution: – Create a trigger of account on after insert and after update.  Invoke  an asynchronous Webservice call with @future annotation to validate the address against google API and return latitude and longitude

Trigger :- 

trigger AccountTriger on Account (after insert) {

    AccountUpdateAsync.updateAccountAddress(Trigger.new[0].Id);

}

Apex Class:-

 public class AccountUpdateAsync {
    @future(callout=true)
    public static void updateAccountAddress(String accId){
        Account acc = [Select Id , Name ,Location__Latitude__s  , Location__Longitude__s, 
                       BillingStreet ,BillingCity ,BillingState ,BillingPostalCode,
                       BillingCountry from Account where id =:accId Limit 1];

        String httpReqURI = 'https://maps.googleapis.com/maps/api/geocode/json?address='+
            acc.BillingStreet+','+acc.BillingCity+','
            +acc.BillingState+','+acc.BillingPostalCode+','+
            acc.BillingCountry
            +'&key=<API_KEY>';
        HttpResponse response = sendHttpReq(httpReqURI);

        if (response.getStatusCode() == 200) {
            JSONParser parser = JSON.createParser(response.getBody());
            Map <String, Object> root = (Map <String, Object>) JSON.deserializeUntyped(response.getBody());
            List <Object> childLevel = (List<Object>) root.get('results');
            for( Object o : childLevel){
                Map <String, Object> childLevel2 = (Map <String, Object>) o;
                Map <String, Object> grandChaildLevel= (Map <String, Object>) childLevel2.get('geometry');
                Object objFinal = grandChaildLevel.get('location');
                Map<String, Object> locs = (Map<String, Object>)objFinal;
                acc.Location__Latitude__s = (Decimal)locs.get('lat') ; 
                acc.Location__Longitude__s = (Decimal)locs.get('lng');
                update acc;
            }

        }

    }

    public static HttpResponse sendHttpReq(String url){
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint(url);
        request.setMethod('GET');
        HttpResponse response = http.send(request);
        return response;

    }

    public static  void parseJson(String json){

    }

}

Future method Considerations:- 

Below are the future method considerations

  1. Methods with the future annotation must be static methods and can only return a void type.
  2. The specified parameters must be primitive data types, arrays of primitive data types, or collections of primitive data types. No sObjects or objects as arguments
  3. The future method does not necessarily execute in the same order it is called.
  4. Methods with the future annotation cannot be used in Visualforce controllers in either getMethodName or setMethodName methods, nor in the constructor.
  5. You cannot call a method annotated with future from a method that also has the future annotation
  6. future calls cannot be made from a batch job
  7. future calls can execute concurrently

 

Best Practices:-

future methods are having its own advantages.  Consider this below best practices while implementing the future calls

  1. Make @future  code is efficient as possible. Long execution times increase the chance of delays and extended delays.
  2.  Minimize the number of the asynchronous requests created to minimize the chance of delay and extended delays.
  3. Make sure you are not invoking too many future calls when you are invoking from the trigger . I would advice one future call for one trigger transaction.
  4. Avoid recursive behavior in future calls.Use a static variable to store the state of the trigger processing
  5. Consider using Batch Apex instead @future to process a large number of records asynchronously.
  6. asynchronous processing framework is queue-based, lower priority than real-time interaction Best practice – ensure @future requests execute as fast as possible and remember limits: 10 @futures each making at most 10 callouts.

 

Limits :-

Future calls have below limits

  1. No more than 10 @future method calls per Apex invocation.
  2. You’re limited to 50 future calls per Apex invocation, and there’s an additional limit on the number of calls in a 24-hour period.  The maximum number of future method invocations per a 24-hour period is 250,000 or the number of user licenses in your organization multiplied by 200, whichever is greater. Still, all salesforce licenses are not applicable fo this limits . for examples chatter licenses are not part of this.  More limits you can refer in salesforce limits guide.