0

I'm trying to do HTTP callout after DML in future method, but I'm getting System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out.

What I'm missing? Is it possible? Test code is below.

public with sharing class UncommittedTest {
  public static void main() {
    dmlAsync();
    callout();
  }

  public static void callout() {
    HttpRequest request = new HttpRequest();
    request.setEndpoint('https://www.google.com');
    request.setMethod('GET');
    HttpResponse response = new Http().send(request);
    System.debug(':::callout: ' + response.getStatusCode() + ' ' + response.getStatus());
  }

  @future
  public static void dmlAsync() {
    Account acc = new Account(Name = 'Test Account ' + DateTime.now());
    insert acc;
    System.debug(':::async dml: ' + acc.Id);
  }
}

// Test in execute anonymous: UncommittedTest.main();
3
1

Even for a future transaction is a transaction which needs to be inserted into an object after which it will get called asynchronously. This DML is what is preventing you from making the callout.

You can instead fire an platform event with type Publish immediately not publish after commit and it will work.

1
  • Great, that's what I'm doing right now. Thank you
    – edelrabe
    Oct 7 '21 at 10:37
1

You can't perform a callout after any modification to the database, including calling future methods. The solution is to make the callout asynchronous instead:

public with sharing class UncommittedTest {
  public static void main() {
    doDml();
    callout();
  }

  @future
  public static void callout() {
    HttpRequest request = new HttpRequest();
    request.setEndpoint('https://www.google.com');
    request.setMethod('GET');
    HttpResponse response = new Http().send(request);
    System.debug(':::callout: ' + response.getStatusCode() + ' ' + response.getStatus());
  }

  public static void doDml() {
    Account acc = new Account(Name = 'Test Account ' + DateTime.now());
    insert acc;
    System.debug(':::async dml: ' + acc.Id);
  }
}

If, for some reason, the DML and callout must both be asynchronous, you'll need to use Queueable instead.

1
  • Thanks, I thought I can fire and forget DML in future method and continue with my callout, but docs are only mentioning future method for callouts, that's why I was confused.
    – edelrabe
    Oct 7 '21 at 10:42

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.