0

I am pretty new to salesforce development. I am trying to make a Callout to the third party API whenever a Account record is created in Salesforce. I tried to make the future callout and didnt realize I need to bulkify the triggers so it threw Too many Future Callouts when I tried to create more than 100 records through data loader. In the other question it was suggested to bulkify the triggers and check the callout limits so i changed my trigger to something 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';     
            if(Limits.getFutureCalls() < Limits.getLimitFutureCalls()) {
             // Calls the future Call method in the Class 
             handleD365Request.createSegSegment(jSONBody,endPoint);                
             }        
            else{
             //not sure how to handle the call out the third party end points if the callout limit has reached
               }  

Currently my apex class 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);
       }
    }

Should I be calling the queueable if the future Callout limit has reached? Or should I be moving my entire logic to queueable as it offers more advantage than the Batch/future. Can anyone suggest how can I be using the queueable here. Appreciate all your help.

2

You can make 100 callouts per transaction. If you want to keep it as a future method, just pass in a list of up to 100 account Ids (less if you also need to get a token or some other callout), or use queueable, and you can chain them together. Every 200 records should require 2 future methods or 1 queueable method (with chaining).


Your trigger is already bulkified, though you do need to handle the "more than 100 callout" problem. Here's an optimized version:

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

    List<String> jSONBody = new List<String>();
    for(Account record: Trigger.new) {
        if(record.RecordTypeId == AccParentRecordTypeId && record.Data_Source_ID__c != null) {
            handleD365Request.SegJSON js = new handleD365Request.SegJSON();
            js.dataAreaId = 'abc';
            js.SegmentCode = acc.Data_Source_ID__c;
            jSONBody.add(json.serialize(js));
            if(jSONBody.size() == 100) {
                handleD365Request.createSegSegment(jSONBody,endPoint);
                jSONBody.clear();
            }
        }
    }
    if(!jSONBody.isEmpty()) {
        handleD365Request.createSegSegment(jSONBody,endPoint);
    }
    
}
| improve this answer | |
  • I am sorry i understood it wrong thought I should be chaining queueable and future together. Can you please help me how I can make two future methods? for every 100 record count should be creating a seperate method? Or should I split the records counts within the trigger to make 100 counts and then call the Apex Class? I am kind of stuck any help is greatly appreciated – user81642 Jun 29 at 16:58
  • @user81642 I modified your code to use the existing future method. Your code was already mostly okay, but you'd have errors in the future methods with more than 100 records passed in. I edited my answer to include how I'd fix the problem. – sfdcfox Jun 29 at 17:23
  • Thank you so much. Just for my Clarification, if we have say 465 records within the for loop the createSegSegment will be called 4 times for every 100 records and if(!jSONBody.isEmpty()) is to execute for the remaining 65 records. Is my understanding correct? – user81642 Jun 29 at 17:32
  • @user81642, triggers are always entered with a "batch" of 200 records. If you do an operation that impacts 200+ records, they will be split up into separate batches with their own transaction limits. That's why sfdcfox said you should need 2 future callouts and not more. – nbrown Jun 29 at 17:51
  • @user81642 Correct, except the maximum in trigger would be 200 records, so it'll always be just once or twice. – sfdcfox Jun 29 at 17:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.