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.

1 Answer 1

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);
    }
    
}
5
  • 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, 2020 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, 2020 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, 2020 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, 2020 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, 2020 at 17:51

You must log in to answer this question.

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