6

My requirement is getting latitude longitude from google map for that i wrote trigger and used @future callouts. now i need to run batch class to update contact records but contacts not updating showing error:

First error: Update failed. First exception on row 0 with id 00328000001hmXdAAI; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, Geolocation: execution of AfterUpdate
caused by: System.AsyncException: Future method cannot be called from a future or batch apex class

closed as off-topic by crmprogdev, dphil, superfell, Adrian Larson, Eric Dec 12 '15 at 0:58

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Questions on problems in code you've written must describe the specific problem and include valid code to reproduce it. For help writing short, self-contained syntactically-valid examples, see: SSCCE.org" – crmprogdev, dphil, superfell, Adrian Larson, Eric
If this question can be reworded to fit the rules in the help center, please edit the question.

  • Your explanation could stand to be expanded on. How does your batch class end up calling an @future method? Is it the same @future method that is grabbing the lat/long from Google? – Derek F Dec 11 '15 at 14:44
  • Is that possible to redesign you application to avoid execution batch/future methods from future methods? because last is impossible Please, post your code -- probably there is a workaround – kurunve Dec 11 '15 at 14:44
  • Hi user123, welcome to SFSE! Please take the time to visit the Help center and read How do I ask a good question. The more details you provide, particularly code you've written, the more likely it is that someone will respond to your question with an answer you'll find helpful. – crmprogdev Dec 11 '15 at 14:47
  • 1
    Can you show your code? You could potentially be causing the trigger to fire off from your future method which in turn would call the future method again. – dphil Dec 11 '15 at 17:41
18

The error is straightforward. To work around it, you need to detect when you're already in an @future or batch context, and then simply not call your @future method(s).

Dan Appleman has a pretty good pattern for this, which he presented at one of his sessions at Dreamforce this year. Defensive Apex Programming

Slides 8-10 are the relevant ones here. For the benefit of others, the defensive @future call pattern looks like this

public void defensiveFutureCall{
    if(System.isFuture() || System.isBatch()){
        regularSyncCall();
    } else {
        if(Limits.getFutureCalls() < Limits.getLimitFutureCalls()){
            doFutureCall();
        } else {
            // Do some explicit notification so that you know your @future call was denied
        }
    }
}

@future
public void doFutureCall(){
    regularSyncCall();
}

public void regularSyncCall(){
    // Put the code, that you'd otherwise put in your @future method, in here
}
0

This is a governor limit provided by salesforce that you cannot call another future method from batch/future method. But, you can always call a batch process from another batch process.

Thanks

Not the answer you're looking for? Browse other questions tagged or ask your own question.