Fix a Batch job that forgets its count
Debug it · Advanced · 20 min · Runs in your Salesforce Developer org · Apex Path
Scenario. A nightly job archives closed Opportunities and posts a Task saying how many. The Opportunities are archived every night, but the Task always says 0.
An archive Batch counts what it changes, but its finish report always says 0. Find out why the counter resets and fix it.
What you will learn
Each execute call of a Batch, and the final finish, runs in its own transaction on a fresh copy of the class. A counter you add to in execute is gone by the time finish runs, so the report says 0.
Database.Stateful carries the instance's fields from one transaction to the next:
public class ArchiveBatch implements Database.Batchable<SObject>, Database.Stateful {
Gotcha. Static variables reset per transaction too. Only instance fields on a Stateful batch survive.
The task
Fix the Batch so finish reports the number of Opportunities execute archived.
Examples:
- 3 closed Opportunities → Task Subject
Archived 3 opportunities - 2 closed and 1 open → the open one is untouched, Subject
Archived 2 opportunities - nothing closed → Subject
Archived 0 opportunities
Requirements:
- Make the counter survive from
executetofinish. - Keep archiving only closed Opportunities, with one update per
execute. - Keep the Task Subject format exactly:
Archived <count> opportunities. - Do not change
start.
Starter code
public class AS_E79CBE2A337D_ArchiveBatch implements Database.Batchable<SObject> {
private Set<Id> opportunityIds;
private Integer archivedCount = 0;
public AS_E79CBE2A337D_ArchiveBatch(Set<Id> opportunityIds) {
this.opportunityIds = opportunityIds;
}
public Database.QueryLocator start(Database.BatchableContext context) {
return Database.getQueryLocator([
SELECT Id
FROM Opportunity
WHERE Id IN :opportunityIds AND IsClosed = true
]);
}
public void execute(Database.BatchableContext context, List<SObject> scope) {
List<Opportunity> updates = new List<Opportunity>();
for (SObject item : scope) {
Opportunity opportunity = (Opportunity) item;
opportunity.Description = 'Archived';
updates.add(opportunity);
}
update updates;
archivedCount += updates.size();
}
public void finish(Database.BatchableContext context) {
insert new Task(Subject = 'Archived ' + archivedCount + ' opportunities');
}
}
When it passes
Closed Opportunities get Description Archived, open ones are untouched, and the finish Task reports the true count, for 0 records or 200.
You write the Apex yourself. ApexSensei runs it and tells you what passed and what did not.