0

I asked another question on the future callouts which was throwing the SystemLimitException, the recommendation was to use the Queable or making the future Callouts bulkified from the trigger. I tried to bulkify the future Callout from the trigger like below

trigger createSegSubSegmentD365 on Account (after insert) {        
    Id AccParentRecordTypeId = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Parent Account').getRecordTypeId();

    List<String> jSONBody = new List<String>();
    
    if(trigger.isinsert)
    {
        set<Id> AccountIds = new Set<Id>();
        list<Account> acclist = new list<Account>();
        for(Account acc : trigger.new){
            AccountIds.add(acc.Id); 
        }

        if(AccountIds.size()>0)
        {
            acclist = [Select id,Data_Source_ID__c,Parent.Data_Source_ID__c,RecordTypeId from Account WHERE Id IN: AccountIds ];                
            for(Account acc : acclist)
            {
                if(acc.RecordTypeId == AccParentRecordTypeId)
                    {
                        if(String.isNotBlank(acc.Data_Source_ID__c) ||String.isNotEmpty(acc.Data_Source_ID__c)) 
                        {
                            handleD365Request.SegJSON js = new handleD365Request.SegJSON();
                            js.dataAreaId = 'abc';
                            js.SegmentCode = acc.Data_Source_ID__c;
                            jSONBody.add(json.serialize(js));
                        }}}           
            
            String endPoint = '/data/ABCParentAccounts';                
            handleD365Request.createSegSegment(jSONBody,endPoint);
        }}}

And my future Callout method is like below

@future (callout=true)
public static void createSegSegment(List<String> jsonBody,String endPoint) {
    ...............
            for (String str : jsonBody)
            {
            Http http1 = new Http();
            HttpRequest req1 = new HttpRequest();
            String d365EndPoint = resource + endPoint;           
            req1.setMethod('POST');
            req1.setTimeout(20000);
            req1.setHeader('Authorization','Bearer '+bearerToken);
            req1.setEndpoint(d365EndPoint);
            req1.setBody(str);
            req1.setHeader('Content-Type', 'application/json;charset=UTF-8');
            HttpResponse res1 = http1.send(req1);
           }
        }

Now when I tested with more than 100 records it worked fine. My question is will my above approach work irrespective of how many number of records are inserted? Will limits on the Callouts needs to be handled because I read that only maximum of 100 callouts per transaction. But when I inserted 116 records through Dataloader the trigger and apex callout worked without any issue. Can anyone suggest if I am missing anything here, new to Salesforce and I appreciate all your help. Thanks

************* Edit ******************** I tried to use check use the getLimitFutureCalls as you suggested in the trigger to make sure we room for the future Callouts but can you please help me how I can move to queueable if the future calls limit is achieved

          if(Limits.getFutureCalls() < Limits.getLimitFutureCalls()) {
           // Calls the future Call method in the Class 
             handleD365Request.createSegSegment(jSONBody,endPoint);                
        }        
         else{
           
        }

Because the Class is currently using the @future callout and I read Queable doesnt work with @future. Appreciate all your help

1 Answer 1

2

The 100 Callouts is a limit per transaction -- since each future is a separate transaction and it only does 1 callout, you are thus not breaching that limit

However, a given synchronous Apex transaction can only make 50 future calls

Your trigger is executed synchronously with Data Loader so if the Data Loader batch size results in more than 50 different accountIds; you will breach this limit. Data Loader batch size can be adjusted in the Data Loader Settings option.

Your trigger can detect before making a future call whether there is headroom to make the next call by using the Limits class

if (Limits.getLimitFutureCalls() == Limits.getFutureCalls()) {
   // defer the remaining accountIds to a queueable that then does callouts

Now, I would be moving all this work out of a trigger and delegate it to a class and use queueables to do the callouts, not future as a queueable can only do 1 future call as you are then in an asynchronous context

As an aside, an interesting pattern to use for scalable async callouts can be found in the book Advanced Apex by Dan Appleman (latest editions)

2
  • I edited my question what I tried. But can you help suggest me how I can can move to queueable if there are no room for future calls.
    – user81642
    Jun 28, 2020 at 3:22
  • given that you accepted the answer; are you still having issues? If so, please post a new question with your current code
    – cropredy
    Jun 29, 2020 at 3:29

You must log in to answer this question.

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