1

Daily orders loads records but some records are missing to load to fix this we have created another batch apex to call each day records and we are comparing with already exists benefitdisbursement records. But we are getting heap size error on HTTP response -(size 9mb). Is there possible to parse response body without hitting heap size? We dont have to any control over third party system. we have only option to request by the date for the single date we are getting 9mb file size. How i can parse the data without hitting heap size?

[![enter image description here][1]][1]

65 line heapsize is 650910 (ie querying existing records to compare with reponse body)

112 - Response: Heap size is 9180509 enforced is 12000000

    Date StartDate;
    Date endDate;
    DateTime stDate;
    DateTime edDate;

    public BT_BD_GetOrdersByMonth(Date StartDate, Date endDate) {
         this.StartDate = StartDate;
         this.endDate = endDate;
         stDate = DateTime.newInstance(startDate.year(), startDate.month(), startDate.day(), 0, 0, 0);
         edDate = DateTime.newInstance(endDate.year(), endDate.month(), endDate.day(), 23, 59, 59);
    }
   
    @TestVisible static Boolean testSwitch = false;
    
    List<BenefitAssignment> baDummy;
    List<Map<String, Object>> responseListMap;
   
    Map<string, id> pcnBAIDMap = new Map<string, id>();
    Map<string, id> pcnPgEnIDMap = new Map<string, id>(); 
    List<BenefitDisbursement> benefitDisbursLst = new List<BenefitDisbursement>();     
    List<BD_300__c> bd300_Lst = new List<BD_300__c>();         

    global Iterable<BenefitDisbursement> start(Database.BatchableContext bc) {
        try {
               // System.debug('BT_BD_BatchApex START  *** stDate >> ' +stDate + ' edDate >> ' + edDate);                  
           //System.debug('System.Label.BT_DummyBA_ID >> ' + System.Label.BT_DummyBA_ID ); 
           
           if(Test.isRunningTest()){
               baDummy = [select Id, ProgramEnrollmentId, StartDateTime, EndDateTime from BenefitAssignment]; 
           }
           else {
               baDummy = [select Id, ProgramEnrollmentId  from BenefitAssignment where id = :System.Label.BT_DummyBA_ID ];                 
           }
           //System.debug('baDummy >> '+baDummy);
           //Get Benefit Assignment records for the Month
           String soqlQuery = 'SELECT Id, Publisher_Customer_Number__c, ProgramEnrollmentId FROM BenefitAssignment WHERE DAY_ONLY(StartDateTime) <= '+stDate.Format('yyyy-MM-dd') +' and DAY_ONLY(EndDateTime) >= '+edDate.Format('yyyy-MM-dd');
           //system.debug('soqlQuery=>'+soqlQuery);         
           List<BenefitAssignment> baLst = database.query(soqlQuery);            
           //System.debug('BenefitAssignment baLst size >> '+baLst.size()); 
           Map<String,id>BenefitDisMap= new Map<String,Id>();
            Map<String,id>BD300Map= new Map<String,Id>();
            
            string soqlQueryBd = 'select id,PCN_BTTCHR__c,Event__c,Student_Id__c,ISBN__c from BenefitDisbursement where Order_Date__c ='+stDate.Format('yyyy-MM-dd');
            system.debug('soqlQueryBd >>>'+soqlQueryBd);
           List<BenefitDisbursement> bdLsts = database.query(soqlQueryBd);  
           
           for(BenefitDisbursement BD:bdLsts){
               BenefitDisMap.put(String.valueOf(BD.PCN_BTTCHR__c+BD.EVENT__c+BD.Student_Id__c+BD.ISBN__c),BD.id);
           }
            bdLsts = new List<BenefitDisbursement>();
            for(BD_300__C BD:[select id,PCN_BTTCHR__c,Event__c,Student_Id__c,ISBN__c from BD_300__C where Order_Date__c=:stDate.Date()]){
               BD300Map.put(String.valueOf(BD.PCN_BTTCHR__c+BD.EVENT__c+BD.Student_Id__c+BD.ISBN__c),BD.id);
           }
            System.debug('Heap Status ' + (limits.getHeapSize()>limits.getLimitHeapSize()));
            system.debug( ': Heap size is ' + limits.getHeapSize() + ' enforced is ' + limits.getLimitHeapSize());  
           //System.debug('BenefitDisMap'+BenefitDisMap);
           // Get the Benefit Assignment ID and PCN Numbers by the data extraction Date   
           Map<string, id>  pcnBAIDMap = new Map<string, id>(); 
           
           for(BenefitAssignment ba :baLst){
              // System.debug('BA ID >>> ' + ba.id);
              //System.debug('BA PCN >>> ' + ba.Publisher_Customer_Number__c);
               pcnBAIDMap.put(ba.Publisher_Customer_Number__c, ba.id);
               pcnPgEnIDMap.put(ba.Publisher_Customer_Number__c, ba.ProgramEnrollmentId);
           }             
           //System.debug('pcnBAIDMap ' + pcnBAIDMap);
           //System.debug('pcnBAIDMap Size' + pcnBAIDMap.size());
           //System.debug('pcnPgEnIDMap Size' + pcnPgEnIDMap.size());

           // Scholastic Production     
           HttpRequest req = new HttpRequest();
           //req.setEndpoint('callout:BTPROD_NC/OrderExtract?startdate=2023-09-01&enddate=2023-09-01');       
           req.setEndpoint('callout:BTPROD_NC/OrderExtract?startdate='+stDate.Format('yyyy-MM-dd')+'&enddate='+edDate.Format('yyyy-MM-dd'));
           
 req.setHeader('Authorization', 'Token ' + System.Label.BT_Scholastic_Token);            
           req.setMethod('GET');
           req.setTimeout(120000);
           
           Http http = new Http();
           String responseBody = '';
           List<Object> responseObject ;
          
           
           //system.debug('In TRY @1 >>>>>>');           
           
           // IF the call is from Test Class get the Mock response data
           if(Test.isRunningTest() && (!testSwitch) ){
               Test.setMock(HttpCalloutMock.class, new BT_BD_MonthlyMockTestData() );
              
           }
//else if(Test.isRunningTest() && testSwitch){
                  //Test.setMock(HttpCalloutMock.class, new BT_Blank_MockCalloutClass() );  
           //}
           System.debug('Before Response Heap Status ' + (limits.getHeapSize()>limits.getLimitHeapSize()));
            system.debug( 'Before Response: Heap size is ' + limits.getHeapSize() + ' enforced is ' + limits.getLimitHeapSize());


           HttpResponse res = http.send(req);
           responseBody = res.getBody();
            System.debug('Response Heap Status ' + (limits.getHeapSize()>limits.getLimitHeapSize()));
            system.debug( 'Response: Heap size is ' + limits.getHeapSize() + ' enforced is ' + limits.getLimitHeapSize());
          
           //System.debug('HTTP Response Body: ' + responseBody);
           
           // Parse the JSON response        
           responseObject = (List<Object>)JSON.deserializeUntyped(responseBody);
            
            
          
           //system.debug('In TRY @2 >>>>>>');
           responseListMap = new List<Map<String, Object>>();      

           for (Object obj : responseObject) {
               responseListMap.add((Map<String, Object>)obj);
           }       
           //System.debug('responseListMap Size >>>> '+ responseListMap.size());
           
           //Iterating the Response Data
           for(Map<String,Object> responsedata : responseListMap){ 
               
               BenefitDisbursement bd = new BenefitDisbursement();                
               String UCN = String.valueof (responsedata.get('BTTCHR')); 
               String orderNo = (String)responsedata.get('EVENT');
               String StuId = (String)responsedata.get('SPSID');
               String ISBN = (String)responsedata.get('ISBN');
               String UCNorderNo=UCN+orderNo+StuId+ISBN;
               String ba_id;                
               String pgEnId;  
               if(!BenefitDisMap.ContainsKey(UCNorderNo)){
                  //System.debug('Entered into If'+UCNorderNo);
                  if(pcnBAIDMap.containsKey(UCN)){
                  // System.debug('In IF >> BA Exists');
                   ba_id = pcnBAIDMap.get(UCN); 
                   pgEnId = pcnPgEnIDMap.get(UCN);                         
                   //System.debug('ba_id>> '+ ba_id + ' pgEnId>> '+ pgEnId);           
               }else{
                   //System.debug('In Else >> BA does not exists');
                   ba_id = baDummy[0].Id; 
                   pgEnId = baDummy[0].ProgramEnrollmentId;                  
               }      
               
               if(orderNo != NUll && !orderNo.startsWith('300')) {
                    //System.debug('Order is Valid //System.debug('Add BD to bdLst');');                  
                    bd.BenefitAssignmentId = ba_id;
                    bd.PCN_BTTCHR__c = UCN;
                    bd.ISBN__c = (String)responsedata.get('ISBN');
                    bd.ITEM__c = (String) responsedata.get('ITEM');
                    bd.Student_ID__c = (String) responsedata.get('SPSID');
                    bd.Price__c = (responsedata.get('PRICE') instanceof String) ? Double.valueOf((String) responsedata.get('PRICE')) : (Double) responsedata.get('PRICE');
                    bd.BTTCHRUCN__c = (String)responsedata.get('BTTCHRUCN');                  
                    bd.EVENT__c=(String)responsedata.get('EVENT');
                    bd.Student_Name__c =(String)responsedata.get('STDNAME');            
                    bd.OFFER__c=(String)responsedata.get('OFFER');
                    bd.CLUB__c=(String)responsedata.get('CLUB');
                    bd.Description=(String)responsedata.get('DESC');
                    bd.ITEM_DESC__c=(String)responsedata.get('ITEMDESC');
                    bd.ProgramEnrollmentId = pgEnId;
                    bd.Record_Created__c = 'Monthly API Callout';
                    String eventDtString = (String) responsedata.get('EVENTDT');                      
                    //System.debug('2 >> eventDtString >> '+ eventDtString); 
                    // EVENT Date & Time   
                    if (eventDtString != null && eventDtString.length() >=10 ) { 
                        //System.debug('2.1 >>');
                        bd.Event_DateTxt__c = eventDtString;
                        String firstTenCharacters = eventDtString.substring(0, 10);
                        //System.debug('First 10 characters: ' + firstTenCharacters);
                        bd.ActualCompletionDate = Datetime.newInstance(Date.valueOf(firstTenCharacters),  Time.newInstance(0, 0, 0, 0));
                        bd.Order_Date__c = Date.valueOf(firstTenCharacters);
                        
                        //System.debug('in IF ActualCompletionDate >>' + bd.ActualCompletionDate + ' Order_Date__c >> '+ bd.Order_Date__c ); 
                    }else{
                            //System.debug('2.2 >>');
                            bd.Event_DateTxt__c = eventDtString;                         
                            Date sterday = Date.today()-1;                         
                            bd.ActualCompletionDate = DateTime.newInstance(sterday.year(), sterday.month(), sterday.day(), 0, 0, 0);                    
                            bd.Order_Date__c = Date.today()-1;
                            //System.debug('in else ActualCompletionDate >>' + bd.ActualCompletionDate + ' Order_Date__c >> '+ bd.Order_Date__c ); 
                    }                  
                    
                    // Quantity
                    //System.debug('3 Quantity>>'); 
                    bd.Total_Quantity__c = (responsedata.get('TOTQTY') instanceof String) ? Double.valueOf((String) responsedata.get('TOTQTY')) : (Double) responsedata.get('TOTQTY');
                    bd.DisbursedQuantity = (responsedata.get('PAIDQTY') instanceof String) ? Double.valueOf((String) responsedata.get('PAIDQTY')) : (Double) responsedata.get('PAIDQTY');
                                  
                    benefitDisbursLst.add(bd);
               }   
               }else{
                    if(!BD300Map.ContainsKey(UCNorderNo) && orderNo.startsWith('300')){
                  //System.debug('Entered into If'+UCNorderNo);
                  if(pcnBAIDMap.containsKey(UCN)){
                  // System.debug('In IF >> BA Exists');
                   ba_id = pcnBAIDMap.get(UCN); 
                   pgEnId = pcnPgEnIDMap.get(UCN);                         
                   //System.debug('ba_id>> '+ ba_id + ' pgEnId>> '+ pgEnId);           
               }else{
                   //System.debug('In Else >> BA does not exists');
                   ba_id = baDummy[0].Id; 
                   pgEnId = baDummy[0].ProgramEnrollmentId;                  
               }  
                    // Load the orders that start with Order Number 300 to BD 300 Object
                    //System.debug('Ignore orders ' );
                    BD_300__c bd3 = new BD_300__c();

                    //System.debug('Order is Valid //System.debug('Add BD to bdLst');');                  
                    bd3.Benefit_AssignmentId__c = ba_id;
                    bd3.Program_EnrollmentId__c = pgEnId;
                    bd3.Record_Created__c = 'Monthly API Callout';
                    bd3.PCN_BTTCHR__c = UCN;
                    bd3.ISBN__c = (String)responsedata.get('ISBN');
                    bd3.ITEM__c = (String)responsedata.get('ITEM');
                    bd3.Student_ID__c = (String)responsedata.get('SPSID');
                    bd3.Price__c = (responsedata.get('PRICE') instanceof String) ? Double.valueOf((String) responsedata.get('PRICE')) : (Double) responsedata.get('PRICE');
                    bd3.BTTCHRUCN__c = (String)responsedata.get('BTTCHRUCN');                  
                    bd3.EVENT__c = (String)responsedata.get('EVENT');
                    bd3.Student_Name__c = (String)responsedata.get('STDNAME');            
                    bd3.OFFER__c = (String)responsedata.get('OFFER');
                    bd3.CLUB__c = (String)responsedata.get('CLUB');
                    bd3.Description__c = (String)responsedata.get('DESC');
                    bd3.ITEM_DESC__c = (String)responsedata.get('ITEMDESC');
                    
                    String eventDtString = (String) responsedata.get('EVENTDT');                      
                    //System.debug('2 >> eventDtString >> '+ eventDtString); 
                    // EVENT Date & Time   
                    if (eventDtString != null && eventDtString.length() >=10 ) { 
                        //System.debug('2.1 >>');
                        bd3.Event_DateTxt__c = eventDtString;
                        String firstTenCharacters = eventDtString.substring(0, 10);
                        //System.debug('First 10 characters: ' + firstTenCharacters);
                        bd3.Actual_Completion_Date__c = Datetime.newInstance(Date.valueOf(firstTenCharacters),  Time.newInstance(0, 0, 0, 0));
                        bd3.Order_Date__c = Date.valueOf(firstTenCharacters);
                        
                        //System.debug('in IF ActualCompletionDate >>' + bd3.ActualCompletionDate + ' Order_Date__c >> '+ bd3.Order_Date__c ); 
                    }else{
                            //System.debug('2.2 >>');
                            bd3.Event_DateTxt__c = eventDtString;                         
                            Date sterday = Date.today()-1;                         
                            bd3.Actual_Completion_Date__c = DateTime.newInstance(sterday.year(), sterday.month(), sterday.day(), 0, 0, 0);                    
                            bd3.Order_Date__c = Date.today()-1;
                            //System.debug('in else ActualCompletionDate >>' + bd3.ActualCompletionDate + ' Order_Date__c >> '+ bd3.Order_Date__c ); 
                    }                  
                    
                    // Quantity                    
                    // System.debug('3 Quantity>>'); 
                    bd3.Total_Quantity__c = (responsedata.get('TOTQTY') instanceof String) ? Double.valueOf((String) responsedata.get('TOTQTY')) : (Double) responsedata.get('TOTQTY');
                    bd3.Disbursed_Quantity__c = (responsedata.get('PAIDQTY') instanceof String) ? Double.valueOf((String) responsedata.get('PAIDQTY')) : (Double) responsedata.get('PAIDQTY');                                 
                
                    bd300_Lst.add(bd3);                         
               }
               }
               //System.debug('FOR END');
           
           }  
           //System.debug('outside for >>');
            

            if (!benefitDisbursLst.isEmpty()) {        
                return benefitDisbursLst;
            } else {
                String importJobId = bc.getJobId();
                //System.debug('importJobId: ' + importJobId);
                //System.abortJob(importJobId);
                return new List<BenefitDisbursement>(); // Return an empty list
            }
        } catch(Exception ex) {
            // Handle exceptions and return an empty list
            return new List<BenefitDisbursement>();
        }
    }```


  [1]: https://i.sstatic.net/LRKmtHhd.png

1 Answer 1

2

In general, you can dump the unnecessary data to try and get your heap under control. You can do this by adding curly braces around the data you want to unload before Apex realizes you're over the heap limit.


{
    System.debug('Before Response Heap Status ' + (limits.getHeapSize()>limits.getLimitHeapSize()));
    System.debug( 'Before Response: Heap size is ' + limits.getHeapSize() + ' enforced is ' + limits.getLimitHeapSize());
    HttpResponse res = http.send(req);
    responseBody = res.getBody();
    System.debug('Response Heap Status ' + (limits.getHeapSize()>limits.getLimitHeapSize()));
    system.debug( 'Response: Heap size is ' + limits.getHeapSize() + ' enforced is ' + limits.getLimitHeapSize());
    //System.debug('HTTP Response Body: ' + responseBody);
    // Parse the JSON response        
    responseObject = (List<Object>)JSON.deserializeUntyped(responseBody);
}
//system.debug('In TRY @2 >>>>>>');
responseListMap = new List<Map<String, Object>>();

Here, the curly braces limit the scope of the response object and response body to just these lines of code. That way, the 9MB response you got back won't be counted more than once.

In your case, this might not be enough to completely eliminate the risk of a heap overflow, but it should reduce the possibility.

3
  • Hi @sfdcfox, Thanks for your response i have added the curly braces. But im getting the same heap size error. In response im receiving values what i needed to store in SF no junk values. { HttpResponse res = http.send(req); responseBody = res.getBody(); System.debug('Response Heap Status ' + (limits.getHeapSize()>limits.getLimitHeapSize())); system.debug( 'Response: Heap size is ' + limits.getHeapSize() + ' enforced is ' + limits.getLimitHeapSize()); responseObject = (List<Object>)JSON.deserializeUntyped(responseBody); } Commented May 9 at 15:01
  • 1
    @Afroseahamed Yeah, it doesn't always work. I have a more aggressive option that may work: responseObject = (List<Object>)JSON.deserializeUntyped(new http().send(req).getBody()); This might give you enough heap to get through.
    – sfdcfox
    Commented May 9 at 17:19
  • Hi @sfdcfox, Thank you so much it worked! Commented May 10 at 9:22

You must log in to answer this question.

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