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
AlaaAlaa 

problem using future method

Hi, am running a future method in a pex class , I call this method in trigger after opportunity update, here is the trigger:

 

Trigger test on Opportunity(after update) {
  OppDateTest.updateOppDate();
  }

 

and here is the class and the future method am calling:

global class OppDateTest{

@future(callout=true)
  public static void updateOppDate() {
 
  Http h = new Http();

// Instantiate a new HTTP request, specify the method (GET) as well as the endpoint  
    String url='http://xxx.xxx.com/xxx/xxx.php';
    HttpRequest req = new HttpRequest();
    req.setEndpoint(url);
    req.setMethod('GET');

// Send the request, and return a response  
    
    HttpResponse res = h.send(req);
    String str=res.getBody();

  Opportunity[] opp = [SELECT id, name FROM Opportunity where name='test'];
    for (Opportunity o : opp) {
     o.description = str;
      update o;
      
      }

 

  }

 

}

 

 

 

but am getting this error whever the trigger fires:

 

 

Failed to invoke future method 'public static void updateOppDate()' on class 'OppDateTest' for job id '707M0000000E4PF'

caused by: System.DmlException: Update failed. First exception on row 0 with id 006M00000026BVNIA2; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, cloudswarm.opptySwarm: execution of AfterUpdate

caused by: System.AsyncException: Future method cannot be called from a future method: cloudswarm.SwarmHelper.evaluateOpptyRules(LIST<Id>)

(cloudswarm): []

Class.OppDateTest.updateOppDate: line 22, column 7
External entry point
Any idead why is this and what does this error mean?
Best Answer chosen by Admin (Salesforce Developers) 
BritishBoyinDCBritishBoyinDC

Since you are updating the opportunity via this trigger, the update is firing twice - first when the record is updated by the user, and then again by the code in the trigger - so the @future is calling another @future during the seciond update.

 

To get round this, you need to add a boolean trigger helper, that you check when the trigger fires to see if it has already been called by this trigger.

 

So a simple class like this:

 

public with sharing class triggerHelper {

public static boolean b=false;
//A boolean that is set and then checked at the beginning of update triggers to be sure they only execute once
public static  void  recursiveHelper (Boolean tempBool){
	b=tempBool;
}

}

 And then in the trigger, add an initial check for the boolean, and set to true:

 

if(!triggerhelper.b){

triggerhelper.recursiveHelper(true);

 Finally, set the boolean to true in the @future class...that way, the trigger won't fire when the @future updates the opportunity record.

 

 

 

 

All Answers

bob_buzzardbob_buzzard

It looks like you've got the cloudswarm package installed, and this has added an after update trigger on the opportunity that is trying to execute an @future method of its own.  As the trigger has fired from your update executed in an @future method, this fails per the apex developer's guide:

 

--- snip ---

 

You cannot call a method annotated with future from a method that also has the future annotation. Nor can you call a trigger from an annotated method that calls another annotated method.

 

--- snip ---

AlaaAlaa

Ok I removed the cloudswarm package and still am getting the exception that I cannot call a future method froma future method? so whats the solution here? I only need to call and HTTP service after opportunity update which has to be in future method.... what can I do here?

BritishBoyinDCBritishBoyinDC

Since you are updating the opportunity via this trigger, the update is firing twice - first when the record is updated by the user, and then again by the code in the trigger - so the @future is calling another @future during the seciond update.

 

To get round this, you need to add a boolean trigger helper, that you check when the trigger fires to see if it has already been called by this trigger.

 

So a simple class like this:

 

public with sharing class triggerHelper {

public static boolean b=false;
//A boolean that is set and then checked at the beginning of update triggers to be sure they only execute once
public static  void  recursiveHelper (Boolean tempBool){
	b=tempBool;
}

}

 And then in the trigger, add an initial check for the boolean, and set to true:

 

if(!triggerhelper.b){

triggerhelper.recursiveHelper(true);

 Finally, set the boolean to true in the @future class...that way, the trigger won't fire when the @future updates the opportunity record.

 

 

 

 

This was selected as the best answer
AlaaAlaa

Amazing !!.. that solved the issue and its working great now

Thank you very much :)