I have an SMS sending requirement, which involves a mix of DML and callouts. I know I can't do DML insert/update before a callout, and I can't do the callout first in my case. Explanation below:
SMS Sequence required:
- Callout to external system to get a link for verification purposes
- Create/insert a record that will receive the verification details from the link the sms recipient clicks on
- Create sms body that includes the link from 1 to send to the recipient who needs to do the verification - this is just a text body and does no query
- Callout to send the sms generated in step 3
- Create a Task to store the sms info sent/returned to show in the Activities timeline on the account (whoId) and the custom verification object (whatId)
- Check the status of the sms (via callout get)
- Update the Task with the sms status
LWC: In our Salesforce org I achieve the above via an LWC which
- Does SMS sequence 1 and 2 in one handleclick function
- If record create in LWC 1 returns success, then does SMS sequence 3, 4, 5
- If LWC 2 above returns success, then does SMS sequence 6 and 7
So the DML and callout mixed error (System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out) doesn't occur when using LWC.
Our portal is built on Heroku platform. A user might be required to do a verification and requests to do so via being sent an SMS or email. The Heroku portal does a callout to the Salesforce org using a class to run steps 1 to 7, but throws the mixed DML/Callout error at SMS 4.
If I make the class Heroku uses do point 4 as an @future(callout=true), then
- the mixed error doesn't happen, but there is no status returned to indicate whether it sent successfully or not so the portal user doesn't know whether the sms was sent or not (unless sent to himself)
- and the Task is not updated as the check doesn't run,
- and I can't run the check because the TaskId (or sms message id) was never returned to the portal so there's no clear id to run a query with. I could potentially use the account (recipient) id and the verification record id though.
Is there any way I can make the SMS sequence run 1 to 7 from Heroku in one call without getting the error? Somehow make 1 and 2 commit before doing the callout at 4, so not having to do my current fix using @future?
UPDATE: I've made the callout to send the SMS an @future method, which means it all works fine. The only thing is the Heroku portal needs to create another callout to retrieve the status of the SMS.
I have a background job running to check Tasks with an SMS status that have not been updated and update them (with a limit of 100 for callout limits).