ApexSensei

Drills › Debug it

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:

  1. Make the counter survive from execute to finish.
  2. Keep archiving only closed Opportunities, with one update per execute.
  3. Keep the Task Subject format exactly: Archived <count> opportunities.
  4. 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.

Try this drill free

You write the Apex yourself. ApexSensei runs it and tells you what passed and what did not.

‹ Fix a mixed DML error