Make Callouts After DML Rollback and Savepoint Release[Explained]

Salesforce actively monitors the IdeaExchange and considers the feedback and suggestions provided by the community when planning future product developments and updates. 

In the Spring ‘24 release, it has acted on many such ideas by delivering new features and updates. One such significant enhancement in Apex is that Salesforce now permits the use of callouts while rolling back DMLs.

In this blog, I will discuss the details of this update, comparing the pre-release and post-release changes with examples and facts. But before that, let me take you back to 2019 when this idea was initially suggested on IdeaExchange.

The DML Rollback Challenge of Danny and Many Others!

Danny, a Salesforce enthusiast, once shared his frustration about the struggle of seamlessly combining DML and callouts.  While executing DML statements before callouts, he was repeatedly getting errors. He encoded that database.rollback, which he was using, was a DML statement causing endless callout loop. 

In the same post, he suggested two recommendations:

1) a validation rule pre-check before committing to DML and

2) callouts without an error message

In Spring ‘24, Salesforce listened to the challenges of developers by introducing a new method for callout i.e. Database.releaseSavepoint. We’ll discuss the need for this method and how it can be executed without any exceptions. 

But before that, let’s check out a few key things first in the next sections.

Handling ‘Uncommitted Work Pending’ Error!

For those of you who are new to this, callouts can not be made inside DMLs. If you were using, Database.rollback(Database.Savepoint) like before, you’ll likely encounter the below error message. 

Handling Uncommitted Work Pending Error in Salesforce Apex

Handling Uncommitted Work Pending Error in Salesforce Apex

This happens because call-outs are typically not allowed in an uncommitted transaction, or a callout cannot happen when a DML is there within the same transaction. Moreover, in languages such as Apex or Java, we don't have commit control, i.e. we can't force commit in Apex.

We'll keep encountering the error message since we can’t force commit or rollback.

Pre-Check of DMLs Before Callout 

To help you understand this limitation, I’ve taken a simple scenario where we create an account from a standard Salesforce UI or a custom LWC. Let’s’ perform some steps to examine this scenario: 

  1. The user enters New Account details on the UI and clicks the SAVE button.

  2. Trigger/Validation Rules/Flows are fired to find duplicates (and validate other business compliance rules)

  3. If there are no duplicates(and other validation failures), it will roll back the transaction, which means it’s good-quality account data.

  4. Rollback is done as the DML was for the sake of deep system validation only.

  5. The system will send new account data to a web service that returns an external ID.

  6. The system stores the new account in SFDC along with the external ID.

Now let me explain the same thing with the help of an example.

apex code for pre-callout DML validation scenario

Sample Apex Code for Pre-callout Data Validation Scenario

So what happened here?

Above, a Savepoint is created, and now you are trying to do DMLs after the Savepoint, which will fire all sorts of validation rules, triggers, and flows, which are doing business integrity and validation checks.

Now when you're rolling back the transaction with Database.rollback(sp); it checks for all the triggering points for error. If there is no error, the account is healthy, has good data, and has good data to send in the transactional context of callout. 

However, the Salesforce ecosystem considers the rollback statement a DML. Because of this, we get the same uncommitted work pending error and can never return to this callout stage.

sp = Database.setSavepoint();

Note: Since insert/update/delete/undelete/merge is DML and so is Rollback, we end up having a deadlock. 

So this is the issue Salesforce is trying to fix in Spring 24 releases, and below is the line where the problem happens.

//Actual WS Callout
String externalID = makeACallout(...data from UI…);

How Spring ‘24 Fixed This Issue?

Salesforce introduced the Database.releaseSavepoint(SP) method to address the challenge of making callouts alongside DML operations. This method allows developers to release savepoints explicitly, providing a solution to the restriction against making callouts within uncommitted transactions.

Previously, callouts after creating savepoints resulted in a CalloutException regardless of whether there was uncommitted DML or the changes were rolled back to a savepoint.

Check out the below example to see what the Spring ‘24 fix looks like for this use case:

Spring ‘24 Fix for Rollback error in Salesforce apex

Spring ‘24 Fix Requires Rollback and Savepoint Release before Callout

Some Corner Conditions To Look At

Let’s have a look at some of the corner conditions Salesforce has mentioned in the Spring ‘24 release notes. 

1. When Callout Is Made without Releasing Savepoint

If you make a callout without releasing SavePoint, you’ll get a Callout Exception, as rollback, Savepoint, and other DML statements are there. In the below example, the Savepoint is not released resulting in an error that all safe points must be released.

2. DML Pending When Callout is Made

This is another corner condition for you to look at. Here Savepoint is created and data is inserted. Now when a callout is made, a CalloutException is informing that the transaction should be rollback before the callout. This happened because you have DML statements pending.

A Quick Exercise For You 💡

Now that you’ve understood this release update and how to navigate the challenge of DML Rollback with the help of HTTP Callouts, it's time to wrap up this blog. 

But before we do, I want you to do this quick exercise.

Debug Logs | Limit Usage Before Spring 24 and After Spring 24

Debug Logs | Limit Usage Before Spring 24 and After Spring 24

Based on the above code, mention the number of 1. DML statements, and 2. DML Rows before and after the Spring 24 release.

Any guesses?

Check the image below. Now, if you execute code, you’ll get 3 DML statements and 1 DML row while you execute this code. This is because, now, only database.rollback (sp); is considered a row compared to previously, where all three lines of code were considered DML rows.

Conclusion

In this blog, I've explained the changes the Spring '24 release brought, particularly how Salesforce now allows DML rollback with web service callouts. This improvement not only streamlines development and saves developers time but also makes Apex transactions more flexible and robust. 

References

1. Make Callouts After Rolling Back DML and Releasing Savepoints

2. DML Rollback Should Allow HttpCallouts

Further Reading

1. Top 10 Apex Updates in Salesforce Spring 24 Release

2. Top 10 Salesforce Flow Builder Enhancements: Spring ‘24 Release Unveiled

3. Top 10 Admin Updates in Salesforce Spring ‘24 Release

Nitish Sharma

Nitish Sharma is a seasoned technical writer with over 5 years of experience in the IT industry. His expertise lies in Salesforce, AI, and Blockchain technologies. Nitish loves writing user-friendly documentation that simplifies complex technical concepts, making them accessible to both novice users and seasoned professionals.

Previous
Previous

Top 10 Salesforce Flow Builder Enhancements: Spring ‘24 Release Unveiled

Next
Next

Top 10 Apex Updates in Salesforce Spring 24 Release