2

I recently faced this question in an interview where I was asked 'Can we make a callout in batch execute after a DML and if yes how?'

I answered:

  • Implement Database.stateful and make a callout in the finish method
  • In execute after DML, I'll call another APEX class to make callout
  • Chain another batch in finish method to make the callout

But none of them seems to be the solution as the callout needs to happen after the DML. What is the best way to achieve this?

2 Answers 2

6

The basic answer is "you can't." DMLs block callouts, so if you need this kind of behavior, you have to arrange an alternative solution.

I solved this very problem in a different manner once. The solution is to do the callouts for the previous execute method in the one that follows, or the finish method for the last execute method.

public class DmlThenCallout implements Database.Batchable<sObject>, Database.Stateful, Database.AllowsCallouts {
  sObject[] previousScope = new sObject[0];
  public Database.QueryLocator start(Database.BatchableContext context) {
    return getQueryLocator(); // whatever that means in your code
  }
  public void execute(Database.BatchableContext context, sObject[] scope) {
    doCalloutsFor(previousScope);
    previousScope = scope;
    performDmlFor(scope);
  }
  public void finish(Database.BatchableContext context) {
    doCalloutsFor(previousScope);
  }
}

This guarantees about as real-time callout as you can have, and it has the added bonus that you don't need to double-down on how many asynchronous limits you're using.

3

The obvious answer is to invoke a future method or enqueue a Queueable that does the callout. You'd call or enqueue with the required details after each DML in execute.

Obviously the future method or Queueable needs the appropriate annotation to allow a callout.

This does have a possible down-side; the DML and callout happen in separate transactions, so you cannot roll back the DML if the callout fails. There isn't a simple way to solve this given how the Salesforce platform functions.

An alternative approach is to arrange for the callout "from the trigger of the records inserted/updated/deleted/undeleted/cloned". You can't actually call out from a trigger, but you'll find some details of how you can arrange for this in a scalable and robust way in this article. This does not solve the separation of the DML and callout into separate transactions.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .