8

Class A is simple page controller. It creates an instance of Class B.

The user can click a button on a VF page to invoke a pagereference method in Class A that will invoke various methods in class B, each of which make one or more callouts. At the end of the of all the callouts, I invoke some final DML statements to avoid the uncommitted error.

But in one method in class B, I sometimes invoke a method in Class B marked with @future to make some additional callouts that can be processed async. Class B will then continue to make some more callouts via other methods in the current context.

But when I invoke the method marked as @future, I suddenly get an "uncommitted work pending" error for all subsequent callouts. But looking through the logs, there is no sign of any DML appearing before the callouts. Any ideas why calling a method marked with @future would cause the "uncommitted work pending" error?

EDIT: Just created this example to demo the problem:

public class CalloutTester {

public Account a;

public CalloutTester() {
    a = new Account();
}

public void SubmitUpdates() {
    insert a;
}

public void Callout1() {


HttpRequest req = new HttpRequest();
  req.setEndpoint('http://www.thomas-bayer.com/sqlrest/CUSTOMER/18/');
  req.setMethod('GET');

    Http http = new Http();
    HTTPResponse res = http.send(req);
    res.getBody();
    a.name = 'Test';
    CalloutTester.Callout1F(); //Comment this out and it works
}

@future(callout=true)
public static void Callout1F() {


HttpRequest req = new HttpRequest();
  req.setEndpoint('http://www.thomas-bayer.com/sqlrest/CUSTOMER/18/');
  req.setMethod('GET');

    Http http = new Http();
    HTTPResponse res = http.send(req);
    res.getBody();

}



public void Callout2() {


HttpRequest req = new HttpRequest();
  req.setEndpoint('http://www.thomas-bayer.com/sqlrest/CUSTOMER/18/');
  req.setMethod('GET');

    Http http = new Http();
    HTTPResponse res = http.send(req);
    res.getBody();
    a.name = 'Test2';
}


}

If you invoke this code in the Anon Console, you'll get an error - but comment out the line calling the @future, and it works fine

CalloutTester ct = new CalloutTester();
    ct.Callout1();
    ct.Callout2();
    ct.SubmitUpdates();
3
  • If you comment out this line in your first method : a.name = 'Test';, does it work? – Boris Bachovski Jan 22 '15 at 22:39
  • 1
    (1) as an aside, a workaround would be to use the Dan Appleman async pattern wherein all future calls are processed by a scheduled job; (2) as a second aside - an upvote for not doing the 'code dump' as so many posters seem to like – cropredy Jan 22 '15 at 22:44
  • Nope - same error - and even if I comment out both a.name = statements, and just set a name in the constructor, it still causes an error. It's as if the very act of invoking a callout is causing the error - because otherwise, the code will run and insert the account with no issue. – BritishBoyinDC Jan 22 '15 at 22:46
4

Making a call to a @future method results in an AsyncApexJob record being created with the JobType of 'Future'. While the DML isn't explicit, a record is being created that would otherwise need to be rolled back in the event of an exception.

If something goes wrong with the subsequent callouts that queued future method call will need to be rolled back. But, then you have the problem of not being able to rollback any successful callouts that occured before the rollback was initiated.

5
  • Ah, I hadn't thought about that as a DML scenario...so the future method can make a callout because it is a new context, but the creation of that future request is considered DML in the current context...ok - let me see how that rollback works then... – BritishBoyinDC Jan 28 '15 at 0:21
  • Yes, I believe that is the case. However, I couldn't find any documentation to back this claim up. It does seem to fit the observed behaviour. That said, it could equally be a bug. – Daniel Ballinger Jan 28 '15 at 0:45
  • 1
    Let me raise a case and see what they say...feels like a bug to me... – BritishBoyinDC Jan 28 '15 at 2:59
  • But what would be the point of "@future (callout=true)" annotations if callouts exceptions were routinely raised because the very act of creating a future context include a DML operation? It seems a catch-22. Did you ever find the answer to your problem? I'm having an identical problem now where I didn't before. – tggagne Apr 13 '16 at 19:14
  • This doesn't make sense, as previous comment explains @tggagne then what would be the point of the future method. Can anyone clarify? – d0001 Jul 22 '16 at 21:33

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.