function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
MikeCampMikeCamp 

Trigger firing in @futuer needs to do callout.

We are co-developing some code with a external vendor.

We wrote some custom code that when certain field on the contact are updated, it creates a record in a sync object(SyncLog).
Then there is a trigger that calls a @future method to send that object to an external system. This is required for callouts in triggers.

This is working fine, however we have NPSP installed.

When the address changes it kicks off a address validation process in the @future context.  If the address gets validated, it updated the contact and the process creates the SyncLog (still in @future)
At this time we get an error - Future method cannot be called from a future or batch method.

So I figure this out and check for @future and call a method without @future.
Then we getan error
 - Http post failed with exception Callout from triggers are currently not supported.

Due to our agreement we are trying to avoid any third party integration utilities.

The callout need to happen in near realtime.

We are caught in a Catch 22.  Does anyone have any suggestions?



Here is a diagram of the problem:
User-added image
Here is the pertinent code.
trigger Code
 
if (!System.isFuture()) {
            SVC_SyncLogService.sendSyncLogFuture(new List<ID>(Trigger.newMap.keySet()));
        } else {
            SVC_SyncLogService.sendSyncLog(new List<ID>(Trigger.newMap.keySet()));
        }



SVC_SyncLogService Code

 
@future (callout=true)
    public static void sendSyncLogFuture(List<ID> SyncLogList) {
        try {
            sendSyncLog(SyncLogList);
        } catch (Exception e) {
            {exception code here}
        }
    }

   public static void sendSyncLog(List<ID> SyncLogList) {
        List<SyncLog__c> SyncLogRecordList = [{select goes here}];
        //if running as part of a test class do not call manager
        if(!Test.isRunningTest()){
            {vendorClass} Mgr = new {vendorClass}();
            Mgr.sendSyncLog(SyncLogRecordList);
        }
    }

 
Best Answer chosen by MikeCamp

All Answers

David Zhu 🔥David Zhu 🔥

It seems your IF ELSE logic has problem.

if (System.isFuture()) {    //should ! sign be removed?
            SVC_SyncLogService.sendSyncLogFuture(new List<ID>(Trigger.newMap.keySet()));
        }
else {
            SVC_SyncLogService.sendSyncLog(new List<ID>(Trigger.newMap.keySet()));
        }
 
MikeCampMikeCamp
@David Zhu -  The ! is a not, so it reads if not future call the @future else call non future.  If you are already in the future, you can't call @future
David Zhu 🔥David Zhu 🔥
First, I would confirm if HTTP Post (I guest it is in method SVC_SyncLogService.sendSyncLog) is working using anonymous apex.
Second, I would put HTTP post code to sendSyncLogFuture method to try.
Third, I would add debug in the code below to check if both 'is future' and 'not future' are called when the trigger is triggered.
if (!System.isFuture()) {
       system.debug('is future');
            SVC_SyncLogService.sendSyncLogFuture(new List<ID>(Trigger.newMap.keySet()));
        } else {
       system.debug('not future'); 
            SVC_SyncLogService.sendSyncLog(new List<ID>(Trigger.newMap.keySet()));
        }


 
MikeCampMikeCamp
@Davis Zhu We spent two day doing that and more. The code all works fine with the exception of Salesforce not allowing callouts in triggers without @future and not detecting trigger callout is already in future. There is no way around the restrictions, so we are looking for alternate solutions that are near real time. Mike Camp Sr Salesforce Administrator/Project Manager (903) 579-3638 (w) (903) 330-6182 (m) www.pinecove.com Christ-Centered. Others-Focused. Seriously Fun. Salesforce Certified Administrator Salesforce Certified Advance Administrator Salesforce Certified Platform App Builder
David Zhu 🔥David Zhu 🔥
I finally got what you meant. Your situation is quite complicated. Just a thought, is it possible to move all logic from Contact Saved to Callout into Address Validation?
David Zhu 🔥David Zhu 🔥
Another thought, instead of using callout from synclog trigger, I would move callout logic to a schedulabe apex class; change synclog trigger to start the schedule job using the schedule class; set the job run in 5 seconds.
MikeCampMikeCamp
This was selected as the best answer