0

I am at my wits end with Future Methods coding and would be very grateful for a working example. I've been reading through the Future Methods documentation here: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_invoking_future_methods.htm.

I am using the following class (below) from the Salesforce Developer docs. I need to understand how to call this exact method and add in the new Account Name 'Test' into the record. Please provide the most basic Trigger to do so. Thanks!

global class FutureMethodExample {

    @future(callout=true)
    public static void getStockQuotes(String acctName) {  

         // Perform a callout to an external service
         acctName.Name = 'Test'; // this is the only line I've added from the doc example
    }
}
  • 2
    What is it you are trying to accomplish? If you lack basic knowledge about Apex, you will likely find much more thorough guidance and hand-holding on the Trailhead platform, where you can learn some of the basic skills you need and get to the point where you are stuck on a specific aspect of the implementation. – Adrian Larson Nov 9 '18 at 18:55
  • I see that you're asking the same questions differently. and you already got a lot of help on the other question. Like @AdrianLarson suggested if your're struggling with basic apex look into trailhead but if you're struggling with a very specific issue I'm sure you're in good hands. Please edit your're question to add the relevant information on what exactly your're trying to achieve and where exactly are you stuck! – codeyinthecloud Nov 9 '18 at 19:05
  • Thanks, guys. I've looked through trailhead but cannot find the relevant answer here. If you have a trailhead module you can point to that would be great as well. – paulK Nov 9 '18 at 19:09
3

Basically if you want to call the above method from a trigger below is how you will do it.

trigger accountTestTrggr on Account (before insert, before update) {
  FutureMethodExample.getStockQuotes(Trigger.new[0].Name); // here the issue isonly the first account will be processed
}

But the issue with your code is its not bulkified(structured to handle processing of multiple records).

The term bulkifying Apex code refers to the concept of making sure the code properly handles more than one record at a time. When a batch of records initiate Apex, a single instance of that Apex code is executed, but it needs to handle all of the records in that given batch. For example, a trigger could be invoked by an Force.com Web Services API call that inserted a batch of records. Or a custom Apex Web Service. So if a batch of records invokes the the same Apex code, all of those records need to be processed as a bulk, in order to write scalable code and avoid hitting governor limits.

Here is an example of poorly written code that only handles one record:

trigger accountTestTrggr on Account (before insert, before update) {

   //This only handles the first record in the Trigger.new collection
   //But if more than 1 Account initiated this trigger, those additional records
   //will not be processed
   Account acct = Trigger.new[0];
   List<Contact> contacts = [select id, salutation, firstname, lastname, email 
              from Contact where accountId = :acct.Id];

}

The issue is that only one Account record is handled because the code explicitly accesses only the first record in the Trigger.new collection by using the syntax Trigger.new[0]. Instead, the trigger should properly handle the entire collection of Accounts in the Trigger.new collection.

Here is a sample of how to handle all incoming records:

trigger accountTestTrggr on Account (before insert, before update) {

   List<String> accountNames = new List<String>{};

   //Loop through all records in the Trigger.new collection
   for(Account a: Trigger.new){
      //Concatenate the Name and billingState into the Description field
      a.Description = a.Name + ':' + a.BillingState
   }

}

Now to bulkify your future method you will do something like below.

global class FutureMethodExample {
  @future
  public static void getStockQuotes(List<Id> recordIds) {
    List<Account> accounts = [Select Id, Name from Account Where Id IN :recordIds];
    // process account records to do awesome stuff may be callouts
  }
}

Now your trigger will look something like below.

trigger accountTestTrggr on Account (after insert, after update) { // after because you want to have the new values preserved for you when you query database and make a callout
  FutureMethodExample.getStockQuotes(Trigger.newMap.keySet()); // Your passing all the Id's instead of one.
}

Look into how to use future methods and definetly take into considerations made by @DavidReed on the other answer in terms of limits and robustness because there is very good chance of blowing up your callout limits with this approach

  • 1
    Minor nitpick; since they're using callouts, they need to split up the keySet in to smaller chunks to avoid blowing governor limits on larger batches. – sfdcfox Nov 9 '18 at 21:12
  • @sfdcfox Valid point. The reason I haven't mentioned it explicitly was David Reed was talking on the same lines in his limits and robustness in the other answer i linked(queueable chaining). Thanks for mentioning – codeyinthecloud Nov 9 '18 at 21:15
0

Here is the solution, in case others get stuck.

trigger Account on Account (before update, after insert) {

    if (Trigger.isAfter) {

        // create list to hold the Account Record ID
        List<String> recordId = new List<String>();

        // create new Account to pull the Account ID
        for (Account acct : Trigger.new) {
            Account a = new Account();
            a.Id = acct.Id;

            // add the Account ID to the recordId List
            recordId.add(a.Id);

            // call the processRecords method and pass the recordId List
            AccountClass.processRecords(recordId);            
        }

    }

    if (Trigger.isAfter) {
        // develop in future
    }

}
  • 2
    AccountClass.processRecords(recordId); should be moved out of the for loop. And you're inserting null values into the recordId also you can just use AccountClass.processRecords(Trigger.newMap.keySet()); to just avoid the for loop – codeyinthecloud Nov 9 '18 at 20:10
  • You are right! I have just finished updating the the trigger and class and everything is working now. I'm going to update this post and the previous ones with the correct solutions. Thanks, codey! – paulK Nov 9 '18 at 22:43

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.