I'm inserting the csv file when my first batch run and then in sub-sequent batch, I'm reading the already inserted csv file and updating the same.
In which case, the amount of memory to hold the string will continue to grow with each subsequent batch that runs. If that's the case, it sounds as though you're going to want to monitor the heap by using getLimitHeapSize()
and getHeapSize()
. Unlike visualforce, I don't think using transient variables will help solve your issue, but it can't hurt either.
If you're creating the final attachment as the sum of a number of chained batch jobs (as opposed to batches in a single job), you'd have the ability to pass the heap used in the previous batch to the next job as a string; updating the string in the finish method of each batch before passing it to the next. I don't believe you can do that with stateful, but you could if the jobs were chained batches (I've done similar in other contexts). I mention that since you show individual queries as opposed to query pointers. If you posted more of your actual code, better guidance could be provided.
EDIT
As requested, below is an example of how to pass a value from one batch job to another using a string variable, manipulated in the finish method and then passed to the next job. Note that this can only be done where you're passing the value where you know the batch will execute once and not in multiple batches for this to work as intended.
public class ClaimUpdateBatch implements Database.Batchable<sObject>{
private final String initialState; // the variable used to pass the state from one batch to another
private final string queryObject;
private final string latestDate;
// the lines below are used to assemble the query strings for each batch
public string queryStr1A = 'SELECT Id, Claim__c FROM Filing__c WHERE Filed__c <= ';
public string queryStr1B = ' AND Outcome__c = null AND Locked__c = false';
public string queryStr2A = 'SELECT Id, Filing__r.Filed__c, Claim_Update__c FROM Investigation__c WHERE Claim__r.Claim_Filed__c <= ';
public string queryStr2B = ' AND Investigation_Outcome__c = null AND Locked__c = false';
public string queryStr3A = 'SELECT Id, Claim_Update__c FROM Litigation__c WHERE Actual_Signature__c = null AND (Draft_Order__c <= ';
public string queryStr3B = ' OR Request_Filed__c <= ';
public string queryStr3C = ') AND Locked__c = false';
string query;
public string queryString1;
public string queryString2;
public string queryString3;
public map<string,string>numToObject;
public integer emailAllowed;
@TestVisible public Id bid;
@TestVisible public Id batchId;
@TestVisible public Id bid1;
public ClaimUpdateBatch(String initialState, string queryObject, string latestDate) {
this.initialState = initialState;
this.latestDate = latestDate;
this.queryObject = queryObject;
queryString1 = queryStr1A + latestDate + queryStr1B;
queryString2 = queryStr2A + latestDate + queryStr2B;
queryString3 = queryStr3A + latestDate + queryStr3B + latestDate + queryStr3C;
getNumToObject();
checkLimits();
}
public void checkLimits(){
Integer emailMax = limits.getLimitEmailInvocations();
Integer emailActual = limits.getEmailInvocations();
emailAllowed = emailMax - emailActual;
if(emailAllowed > 2) Messaging.reserveSingleEmailCapacity(2);
}
public void getNumToObject(){
// map of the string value to the sobject string the batch will operate on
numToObject = new map<string,string>();
numToObject.put('1','Filing__c');
numToObject.put('2','Investigation__c');
numToObject.put('3','Litigation__c');
}
@TestVisible public Database.QueryLocator start(Database.BatchableContext BC) {
bid = Test.isRunningTest()? '707000000000000AAA': BC.getJobId();
If(initialState == '1' && numToObject.get(initialState)=='Filing__c') query = queryString1;
If(initialState == '2' && numToObject.get(initialState)=='Investigation__c') query = queryString2;
If(initialState == '3' && numToObject.get(initialState)=='Litigation__c') query = queryString3;
system.debug('query = ' + query);
return Database.getQueryLocator(query);
}
public void execute(Database.BatchableContext BC,
List<sObject> scope) {
if(this.initialState == '1'){
list<Petition__c>ToUpdate = new list<Filing__c>();
for(sObject s : scope){Filing__c f = (Filing__c)s;
f.Claim_Update__c = !f.Claim_Update__c;
ToUpdate.add(f);
}
update toupdate;
} else if(this.initialState == '2'){
list<Investigation__c>ToUpdate = new list<Investigation__c>();
for(sObject s : scope){Investigation__c n = (Investigation__c)s;
n.Claim_Update__c=!n.Claim_Update__c;
ToUpdate.add(n);
}
update toupdate;
} else if(this.initialState == '3'){
list<Litigation__c>ToUpdate = new list<Litigation__c>();
for(sObject s : scope){Litigation__c l = (Litigation__c)s;
l.Claim_Update__c=!l.Claim_Update__c;
ToUpdate.add(l);
}
update toupdate;
}
}
@TestVisible public void finish(Database.BatchableContext BC) {
system.debug('emailAllowed = ' + emailAllowed);
system.debug('app.Primary_Admin__c = ' + app.Primary_Admin__c);
system.debug('app.Org_Admin__c = ' + app.Org_Admin__c);
bid = Test.isRunningTest()? '707000000000000AAA': BC.getJobId();
if(emailAllowed>1 ){
AsyncApexJob aaj = new AsyncApexJob();
if(bid != '707000000000000AAA'){
aaj = [SELECT Id, Status, JobItemsProcessed, TotalJobItems, NumberOfErrors
FROM AsyncApexJob WHERE Id = :bid ];
}
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[]{app.Primary_Admin__c};
string[] ccAddresses = new string[]{app.Org_Admin__c};
mail.setToAddresses(toAddresses);
mail.setCcAddresses(ccAddresses);
mail.setReplyTo('[email protected]');
mail.setSenderDisplayName('Claims Update Batch Processing Job number ' + aaj.Id );
mail.setSubject('Claims Update Process Completed');
mail.setPlainTextBody('Batch Process ' + aaj.Id + ' has completed on '+ numToObject.get(initialState) + ' object records with a Status of ' + aaj.Status +
'. There were ' + aaj.JobItemsProcessed + ' job items processed with ' + aaj.NumberOfErrors + ' errors.' );
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
// below is the means of manipulating the string in this batch when creating the next batch.
// could use a similar technique to capture the heap and send it to the next batch
// start next job
if(integer.valueof(initialState)<3){
string nextInitialState = string.valueOf(integer.valueOf(initialState) +1);
system.debug(nextInitialState);
string nextQueryObject = numToObject.get(nextInitialState);
batchId = Database.executeBatch(new ClaimUpdateBatch(nextInitialState, nextQueryObject, latestDate));
System.debug('Returned batch process ID: ' + batchId);
}
if(null != batchId) bid1 = batchId;
}
}