0

I am confused on the wording of the documentation on Apex Batch Class: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm

I have my batch class querying for 200k records. To my understanding, it is in a batch class and it should chunk each scope list into 200 records, process those records then go back to the query and pull out the next 200 records. Is this incorrect? Should I be putting a LIMIT 200 on my query? When I run the class and hit the webservice in ConsoleApplicationLinkController.getShortenedLinkBULKNOTFUTURE() for some reason it is hitting the service twice. See picture. It looks as if it is in a loop and is processing the previous batch of 200 processed records + the 200 new records. Does my code look right?

global with sharing class BatchBackFillContactsPardot implements Database.Batchable<sObject>,Database.AllowsCallouts,Database.Stateful{
public List<String> valContactList = new List<String>();
global final String queryContact = 'SELECT Id,pi__url__c, Account.Web_Id_NatFund__c FROM Contact WHERE pi__url__c != NULL AND Account.Web_Id_NatFund__c != NULL AND Encrypted_Email_String__c = NULL ORDER BY Name ASC';
global String valContacts;
global String valLeads = null;

global Database.QueryLocator start(Database.BatchableContext bc) {
    return Database.getQueryLocator(queryContact);
}

global void execute(Database.BatchableContext bc, Contact[] scope) {
    for(Contact c : scope){
        valContacts = '{"ID":"' + c.Id+'","Properties":{"NFD":"' + c.Account.Web_Id_NatFund__c + '", "ContactId":"' +c.id+'","GeneratingTime":"' + Date.today().format() + '"}}';
        valContactList.add(valContacts);
    }
    if(valContactList.size()>1){
        valContacts = string.join(valContactList,',');
        system.debug('valLeads.length():: ' + valContacts.length() + ', bulk: ' + valContactList);
    }
    else {
        system.debug('list size is one');
    }
    try {
        ConsoleApplicationLinkController.getShortenedLinkBULKNOTFUTURE(valContacts, valLeads);
    }
    catch (System.CalloutException e){
        system.debug('Error: ' + e);
    }
}

global void finish(Database.BatchableContext BC) {
    system.debug('finished batchable:' + bc);
}
}

enter image description here

3

This behavior is caused by using Database.Stateful and a class-level array. You're basically storing the execution of each previous run and adding to it. Here's how you'd fix that:

global with sharing class BatchBackFillContactsPardot implements Database.Batchable<sObject>,Database.AllowsCallouts {
    // ... omitting start method ... //
    global void execute(Database.BatchableContext bc, Contact[] scope) {
        List<String> valContactList = new List<String>();
        for(Contact c : scope){
            String valContacts = '{"ID":"' + c.Id+'","Properties":{"NFD":"' + c.Account.Web_Id_NatFund__c + '", "ContactId":"' +c.id+'","GeneratingTime":"' + Date.today().format() + '"}}';
            valContactList.add(valContacts);
        // ... rest of code ... //
    }
    // ... omitting finish method ... //
}

In general, you should only use Database.Stateful when you need to aggregate data together across runs. Also, only use class-level variables when you need to share data across execute methods.

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.