Salesforce Developer – Batch & Scheduled Apex Questions

Batch and Scheduled Apex are essential for processing large data volumes and automating time-based operations in Salesforce. These questions cover batch Apex implementation, start/execute/finish methods, batch size considerations, error handling in batches, scheduled Apex patterns, cron expression syntax, chaining batch jobs, governor limit management, monitoring batch execution, aborting scheduled jobs, complex batch scenarios, performance optimization, testing strategies, and integration with external systems. Understanding these concepts is crucial for handling large-scale data processing and automation.

Batch & Scheduled Apex - Q&A

  1. Q1. What is Batch Apex and when would you use it?
    Ans: Batch Apex processes large data volumes by breaking them into smaller chunks (batches). It's used when: - Processing > 10,000 records - Complex data operations that exceed governor limits - Data cleanup/migration tasks - Integration with external systems - Complex calculations on large datasets
  2. Q2. Explain the three methods of the Database.Batchable interface.
    Ans: The three methods are: 1. start(): Collects records to process (Database.QueryLocator or Iterable) 2. execute(): Processes each batch of records (called for each batch) 3. finish(): Cleanup/summary operations (called once at the end) Example:
    public class AccountBatchProcessor implements Database.Batchable {
      public Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator([SELECT Id FROM Account WHERE Status__c = 'Inactive']);
      }
      
      public void execute(Database.BatchableContext bc, List scope) {
        // Process batch of accounts
        for(Account acc : scope) {
          acc.Status__c = 'Archived';
        }
        update scope;
      }
      
      public void finish(Database.BatchableContext bc) {
        // Send completion email or log results
      }
    }
  3. Q3. How do you determine the appropriate batch size?
    Ans: Batch size considerations: - Default: 200 records per batch - Adjust based on: * Complexity of execute() logic * Governor limit consumption * Processing time per record - Optimal range: 100-2000 records - Example:
    Database.executeBatch(new AccountBatchProcessor(), 500);
  4. Q4. How do you handle errors in Batch Apex?
    Ans: Error handling approaches: - Try-catch blocks in execute() method - Partial success with Database methods - Logging errors to custom objects - Retry mechanism for transient failures Example:
    public void execute(Database.BatchableContext bc, List scope) {
      Database.SaveResult[] results = Database.update(scope, false);
      for(Integer i = 0; i < results.size(); i++) {
        if(!results[i].isSuccess()) {
          // Log error for failed record
          System.debug('Failed: ' + scope[i].Id + ' - ' + results[i].getErrors()[0].getMessage());
        }
      }
    }
  5. Q5. What is Scheduled Apex and how do you implement it?
    Ans: Scheduled Apex runs at specific times using cron expressions. Implementation:
    global class AccountCleanupScheduler implements Schedulable {
      global void execute(SchedulableContext sc) {
        // Execute batch job
        Database.executeBatch(new AccountBatchProcessor());
      }
    }
    
    // Scheduling via Anonymous Apex:
    System.schedule('Daily Account Cleanup', '0 0 2 * * ?', new AccountCleanupScheduler());
  6. Q6. Explain cron expression syntax in Salesforce.
    Ans: Cron expression format: Seconds Minutes Hours Day_of_month Month Day_of_week Year Examples: - '0 0 2 * * ?' - Daily at 2 AM - '0 0 12 ? * MON-FRI' - Weekdays at 12 PM - '0 0 0 1 * ?' - First day of every month at midnight - '0 0 3 ? * SUN' - Every Sunday at 3 AM
  7. Q7. How do you chain batch jobs together?
    Ans: Chaining in finish() method:
    public void finish(Database.BatchableContext bc) {
      // Chain to next batch job
      if(needsMoreProcessing) {
        Database.executeBatch(new NextBatchProcessor(), 200);
      }
      
      // Or call scheduled job
      System.schedule('Next Job', '0 0 3 * * ?', new NextScheduler());
    }
  8. Q8. What are the governor limits for Batch and Scheduled Apex?
    Ans: Key limits: - Batch jobs: 5 concurrent batches per org - Scheduled jobs: 100 scheduled jobs per org - Execute method: 10,000 records per batch - Async calls: 250,000 per 24 hours - Heap size: 12MB for async contexts - Execution time: 10 minutes for sync, 60 minutes for async
  9. Q9. How do you monitor batch job execution?
    Ans: Monitoring options: - Setup → Environments → Jobs → Bulk Data Loads - Setup → Environments → Jobs → Scheduled Jobs - Apex Jobs in Developer Console - AsyncApexJob object queries - Custom logging in finish() method Example query:
    SELECT Id, Status, JobItemsProcessed, TotalJobItems, NumberOfErrors 
                  FROM AsyncApexJob 
                  WHERE JobType = 'BatchApex'
  10. Q10. How do you abort a scheduled job?
    Ans: Aborting methods: - Setup UI: Setup → Environments → Jobs → Scheduled Jobs → Delete - Apex:
    List jobs = [SELECT Id FROM CronTrigger WHERE CronJobDetail.Name = 'JobName'];
    for(CronTrigger job : jobs) {
      System.abortJob(job.Id);
    }
    - Get job ID when scheduling:
    CronTrigger ct = new CronTrigger();
    ct.CronExpression = '0 0 2 * * ?';
    String jobId = System.schedule('JobName', ct.CronExpression, new Scheduler());
    // Later: System.abortJob(jobId);
  11. Q11. Can you give an example of a complex batch scenario?
    Ans: Complex scenario - Data archiving with dependencies:
    public class ComplexDataArchiver implements Database.Batchable, Database.Stateful {
      private Integer processedCount = 0;
      private List errors = new List();
      
      public Database.QueryLocator start(Database.BatchableContext bc) {
        // Complex query with subqueries
        return Database.getQueryLocator([
          SELECT Id, Name, (SELECT Id FROM Contacts), (SELECT Id FROM Opportunities) 
          FROM Account 
          WHERE LastModifiedDate < LAST_N_YEARS:2
        ]);
      }
      
      public void execute(Database.BatchableContext bc, List scope) {
        try {
          // Process related records first
          List contactsToDelete = new List();
          List opportunitiesToArchive = new List();
          
          for(Account acc : scope) {
            contactsToDelete.addAll(acc.Contacts);
            opportunitiesToArchive.addAll(acc.Opportunities);
          }
          
          // Delete contacts
          if(!contactsToDelete.isEmpty()) {
            delete contactsToDelete;
          }
          
          // Archive opportunities
          if(!opportunitiesToArchive.isEmpty()) {
            for(Opportunity opp : opportunitiesToArchive) {
              opp.IsArchived__c = true;
            }
            update opportunitiesToArchive;
          }
          
          // Update account status
          for(Account acc : scope) {
            acc.Status__c = 'Archived';
          }
          update scope;
          
          processedCount += scope.size();
        } catch(Exception e) {
          // Log error
          errors.add(new Error_Log__c(
            Message__c = e.getMessage(),
            Stack_Trace__c = e.getStackTraceString()
          ));
        }
      }
      
      public void finish(Database.BatchableContext bc) {
        // Log completion
        if(!errors.isEmpty()) {
          insert errors;
        }
        
        // Send notification
        Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
        email.setToAddresses(new String[]{'admin@company.com'});
        email.setSubject('Batch Archive Complete');
        email.setPlainTextBody('Processed ' + processedCount + ' accounts');
        Messaging.sendEmail(new Messaging.SingleEmailMessage[]{email});
      }
    }
  12. Q12. How do you optimize batch job performance?
    Ans: Performance optimization techniques: - Efficient queries: Use selective WHERE clauses - Batch size tuning: Adjust based on complexity - Minimize DML: Combine operations - Use maps/sets: For efficient lookups - Avoid SOQL/SOSL in loops: Move outside execute() - Stateful batches: For cross-batch data sharing - Parallel processing: Multiple batch jobs for independent data Example with optimization:
    public void execute(Database.BatchableContext bc, List scope) {
      // Efficient query with map
      Map> accountContacts = new Map>();
      for(Contact c : [SELECT Id, AccountId FROM Contact WHERE AccountId IN :scope]) {
        if(!accountContacts.containsKey(c.AccountId)) {
          accountContacts.put(c.AccountId, new List());
        }
        accountContacts.get(c.AccountId).add(c);
      }
      
      // Process accounts with their contacts
      for(Account acc : scope) {
        List contacts = accountContacts.get(acc.Id);
        // Process account and contacts together
      }
    }
  13. Q13. How do you test Batch and Scheduled Apex?
    Ans: Testing strategies: - Test data volume: Create enough records to trigger batching - Test.startTest()/stopTest(): Forces synchronous execution - Verify results: Check database state after execution - Error handling: Test failure scenarios - Scheduled jobs: Verify cron expression and execution Example test:
    @isTest
    static void testAccountBatchProcessor() {
      // Create test data
      List testAccounts = new List();
      for(Integer i = 0; i < 200; i++) {
        testAccounts.add(new Account(Name = 'Test ' + i, Status__c = 'Inactive'));
      }
      insert testAccounts;
      
      // Test batch execution
      Test.startTest();
      Database.executeBatch(new AccountBatchProcessor(), 50);
      Test.stopTest();
      
      // Verify results
      List updatedAccounts = [SELECT Id, Status__c FROM Account WHERE Id IN :testAccounts];
      for(Account acc : updatedAccounts) {
        System.assertEquals('Archived', acc.Status__c);
      }
    }
  14. Q14. How do you integrate Batch Apex with external systems?
    Ans: Integration patterns: - Callout in execute(): For each batch - Callout in finish(): Summary data - Platform Events: Real-time notifications - Queueable Apex: For complex callout chains Example with callout:
    public void execute(Database.BatchableContext bc, List scope) {
      // Prepare data for external system
      List externalData = new List();
      for(Account acc : scope) {
        externalData.add(new ExternalAccountData(acc.Name, acc.Type));
      }
      
      // Make callout
      Http http = new Http();
      HttpRequest request = new HttpRequest();
      request.setEndpoint('https://api.external.com/accounts');
      request.setMethod('POST');
      request.setBody(JSON.serialize(externalData));
      request.setHeader('Content-Type', 'application/json');
      
      HttpResponse response = http.send(request);
      if(response.getStatusCode() != 200) {
        // Handle error
        System.debug('Callout failed: ' + response.getBody());
      }
    }
  15. Q15. What are the best practices for Batch and Scheduled Apex?
    Ans: Best practices: - Keep batches small: Process manageable chunks - Handle errors gracefully: Don't let one record fail the batch - Use Stateful batches: When you need to maintain state - Monitor execution: Log progress and errors - Test thoroughly: Cover success, failure, and edge cases - Document cron expressions: For maintenance - Consider alternatives: Platform Events, Queueable for simpler cases - Respect limits: Don't consume unnecessary resources - Plan for failures: Implement retry logic for transient errors

Back to Developer Home