I'm trying to execute the same batch class for a series of dates and I want each batch to process after the previous one has completed. I'm not sure, from an architecture standpoint how to achieve this. I don't think I need to implement Database.Stateful as I won't be incrementing my variable in the execute method, but instead at the end.
I don't work with batch Apex too often, but I'd really like to pass a date variable to the batch class, and then, after the batch finishes with all records for that date, increment that date and process again for the next date (until I reach today).
I imagine this looks something like this, but I'm not sure of the exact methodology:
global class MyBatchClass implements Database.Batchable<SObject>{
String queryBegin = 'some SOQL Query WHERE CreatedDate = ';
public Date d;
String query = queryBegin + String.valueOf(d);
global Database.QueryLocator start(Database.BatchableContext bc){
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext bc, List<SObject> scope){
//do stuff
}
global void finish(Database.BatchableContext bc){
//queue up next one
d += 1;
if(d <= Date.today()){
Database.executeBatch(new MyBatchClass(d));
}
}
}
In the execute method, I'll be finding records related to the records returned in the start method, but I need to grab them one date at a time. I know the above isn't quite right, but any help here is much appreciated.
*********EDIT*********
I took the advice @sfdcfox and now if I try to queue this up, I just get runaway Apex. It continues to execute an infinite number of batch jobs. I added some debug statements to the finish method to try and track the issue down, and it seems to increment the DateTime variables, but when it chains the next job, those values aren't carried over. It doesn't seem to matter if I use Database.executeBatch(this)
or new MyBatchClass(startDateTime.date())
.
public class MyBatchClass implements Database.Batchable<SObject>{
DateTime startDateTime, endDateTime;
public MyBatchClass(Date firstDate){
startDateTime = DateTime.newInstance(firstDate, Time.newInstance(0,0,0,0));
endDateTime = startDateTime.addDays(1);
}
public Database.QueryLocator start(Database.BatchableContext bc){
return Database.getQueryLocator([SELECT Fields
FROM SObject
WHERE CreatedDate >= :startDateTime
AND CreatedDate < :endDateTime]);
}
public void execute(Database.BatchableContext bc, List<SObject> scope){
//do stuff
}
public void finish(Database.BatchableContext bc){
Date yestDay = Date.today()-1;
startDateTime.addDays(1);
endDateTime.addDays(1);
if(startDateTime.date() < yestDay){
//Database.executeBatch(this);
//Database.executeBatch(new MyBatchClass(startDateTime.date()));
}
}
}
I don't think it matters, but I'm in a dev org where there is no data returned by the query locator, so nothing happens in the execute method. I'm just trying to test the chaining functionality.