Tuesday, October 31, 2017

Using Batch Apex

To use batch Apex, write an Apex class that implements the Salesforce-provided interface Database.Batchable and then invoke the class programmatically.
To monitor or stop the execution of the batch Apex job, from Setup, enter Apex Jobs in the Quick Find box, then select Apex Jobs.

Implementing the Database.Batchable Interface

The Database.Batchable interface contains three methods that must be implemented.
  • start method:
    1global (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc) {}
    To collect the records or objects to pass to the interface method execute, call the start method at the beginning of a batch Apex job. This method returns either a Database.QueryLocator object or an iterable that contains the records or objects passed to the job.
    When you’re using a simple query (SELECT) to generate the scope of objects in the batch job, use the Database.QueryLocator object. If you use a QueryLocator object, the governor limit for the total number of records retrieved by SOQL queries is bypassed. For example, a batch Apex job for the Account object can return a QueryLocatorfor all account records (up to 50 million records) in an org. Another example is a sharing recalculation for the Contact object that returns a QueryLocator for all account records in an org.
    Use the iterable to create a complex scope for the batch job. You can also use the iterable to create your own custom process for iterating through the list.
    Important
    If you use an iterable, the governor limit for the total number of records retrieved by SOQL queries is still enforced.
  • execute method:
    1global void execute(Database.BatchableContext BC, list<P>){}
    To do the required processing for each chunk of data, use the execute method. This method is called for each batch of records that you pass to it.
    This method takes the following:
    • A reference to the Database.BatchableContext object.
    • A list of sObjects, such as List<sObject>, or a list of parameterized types. If you are using a Database.QueryLocator, use the returned list.
    Batches of records tend to execute in the order in which they’re received from the start method. However, the order in which batches of records execute depends on various factors. The order of execution isn’t guaranteed.
  • finish method:
    1global void finish(Database.BatchableContext BC){}
    To send confirmation emails or execute post-processing operations, use the finish method. This method is called after all batches are processed.
Each execution of a batch Apex job is considered a discrete transaction. For example, a batch Apex job that contains 1,000 records and is executed without the optional scope parameter from Database.executeBatch is considered five transactions of 200 records each. The Apex governor limits are reset for each transaction. If the first transaction succeeds but the second fails, the database updates made in the first transaction are not rolled back.

Using Database.BatchableContext

All the methods in the Database.Batchable interface require a reference to a Database.BatchableContext object. Use this object to track the progress of the batch job.
The following is the instance method with the Database.BatchableContext object:
NameArgumentsReturnsDescription
getJobIDIDReturns the ID of the AsyncApexJob object associated with this batch job as a string. Use this method to track the progress of records in the batch job. You can also use this ID with the System.abortJob method.
The following example uses the Database.BatchableContext to query the AsyncApexJob associated with the batch job.
01global void finish(Database.BatchableContext BC){
02   // Get the ID of the AsyncApexJob representing this batch job
03   // from Database.BatchableContext.
04   // Query the AsyncApexJob object to retrieve the current job's information.
05   AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed,
06      TotalJobItems, CreatedBy.Email
07      FROM AsyncApexJob WHERE Id =
08      :BC.getJobId()];
09   // Send an email to the Apex job's submitter notifying of job completion.
10   Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
11   String[] toAddresses = new String[] {a.CreatedBy.Email};
12   mail.setToAddresses(toAddresses);
13   mail.setSubject('Apex Sharing Recalculation ' + a.Status);
14   mail.setPlainTextBody
15   ('The batch Apex job processed ' + a.TotalJobItems +
16   ' batches with '+ a.NumberOfErrors + ' failures.');
17   Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
18}

Using Database.QueryLocator to Define Scope

The start method can return either a Database.QueryLocator object that contains the records to use in the batch job or an iterable.
The following example uses a Database.QueryLocator:
01global class SearchAndReplace implements Database.Batchable<sObject>{
02 
03   global final String Query;
04   global final String Entity;
05   global final String Field;
06   global final String Value;
07 
08   global SearchAndReplace(String q, String e, String f, String v){
09 
10      Query=q; Entity=e; Field=f;Value=v;
11   }
12 
13   global Database.QueryLocator start(Database.BatchableContext BC){
14      return Database.getQueryLocator(query);
15   }
16 
17   global void execute(Database.BatchableContext BC, List<sObject> scope){
18     for(sobject s : scope){
19     s.put(Field,Value);
20     }
21     update scope;
22    }
23 
24   global void finish(Database.BatchableContext BC){
25   }
26}

Using an Iterable in Batch Apex to Define Scope

The start method can return either a Database.QueryLocator object that contains the records to use in the batch job or an iterable. Use an iterable to step through the returned items more easily.
01global class batchClass implements Database.batchable{
02   global Iterable start(Database.BatchableContext info){
03       return new CustomAccountIterable();
04   }    
05   global void execute(Database.BatchableContext info, List<Account> scope){
06       List<Account> accsToUpdate = new List<Account>();
07       for(Account a : scope){
08           a.Name = 'true';
09           a.NumberOfEmployees = 70;
10           accsToUpdate.add(a);
11       }
12       update accsToUpdate;
13   }    
14   global void finish(Database.BatchableContext info){    
15   }
16}

Using the Database.executeBatch Method to Submit Batch Jobs

You can use the Database.executeBatch method to programmatically begin a batch job.
Important
When you call Database.executeBatch, Salesforce adds the process to the queue. Actual execution can be delayed based on service availability.
The Database.executeBatch method takes two parameters:
  • An instance of a class that implements the Database.Batchable interface.
  • An optional parameter scope. This parameter specifies the number of records to pass into the execute method. Use this parameter when you have many operations for each record being passed in and are running into governor limits. By limiting the number of records, you are limiting the operations per transaction. This value must be greater than zero. If the start method of the batch class returns a QueryLocator, the optional scope parameter of Database.executeBatch can have a maximum value of 2,000. If set to a higher value, Salesforce chunks the records returned by the QueryLocator into smaller batches of up to 2,000 records. If the start method of the batch class returns an iterable, the scope parameter value has no upper limit. However, if you use a high number, you can run into other limits.
The Database.executeBatch method returns the ID of the AsyncApexJob object, which you can use to track the progress of the job. For example:
1ID batchprocessid = Database.executeBatch(reassign);
2 
3AsyncApexJob aaj = [SELECT Id, Status, JobItemsProcessed, TotalJobItems, NumberOfErrors
4                    FROM AsyncApexJob WHERE ID =: batchprocessid ];
You can also use this ID with the System.abortJob method.
For more information, see AsyncApexJob in the Object Reference for Salesforce and Force.com.

Holding Batch Jobs in the Apex Flex Queue

With the Apex flex queue, you can submit up to 100 batch jobs.
The outcome of Database.executeBatch is as follows.
  • The batch job is placed in the Apex flex queue, and its status is set to Holding.
  • If the Apex flex queue has the maximum number of 100 jobs, Database.executeBatch throws a LimitException and doesn’t add the job to the queue.
Note
If your org doesn’t have Apex flex queue enabled, Database.executeBatch adds the batch job to the batch job queue with the Queued status. If the concurrent limit of queued or active batch job has been reached, a LimitException is thrown, and the job isn’t queued.
Reordering Jobs in the Apex Flex Queue
While submitted jobs have a status of Holding, you can reorder them in the Salesforce user interface to control which batch jobs are processed first. To do so, from Setup, enter Apex Flex Queue in the Quick Find box, then select Apex Flex Queue.
Alternatively, you can use Apex methods to reorder batch jobs in the flex queue. To move a job to a new position, call one of the System.FlexQueue methods. Pass the method the job ID and, if applicable, the ID of the job next to the moved job’s new position. For example:
1Boolean isSuccess = System.FlexQueue.moveBeforeJob(jobToMoveId, jobInQueueId);
You can reorder jobs in the Apex flex queue to prioritize jobs. For example, you can move a batch job up to the first position in the holding queue to be processed first when resources become available. Otherwise, jobs are processed “first-in, first-out”—in the order in which they’re submitted.
When system resources become available, the system picks up the next job from the top of the Apex flex queue and moves it to the batch job queue. The system can process up to five queued or active jobs simultaneously for each organization. The status of these moved jobs changes from Holding to Queued. Queued jobs get executed when the system is ready to process new jobs. You can monitor queued jobs on the Apex Jobs page.

Batch Job Statuses

The following table lists all possible statuses for a batch job along with a description of each.
StatusDescription
HoldingJob has been submitted and is held in the Apex flex queue until system resources become available to queue the job for processing.
QueuedJob is awaiting execution.
PreparingThe start method of the job has been invoked. This status can last a few minutes depending on the size of the batch of records.
ProcessingJob is being processed.
AbortedJob aborted by a user.
CompletedJob completed with or without failures.
FailedJob experienced a system failure.

Using the System.scheduleBatch Method

You can use the System.scheduleBatch method to schedule a batch job to run once at a future time.
The System.scheduleBatch method takes the following parameters.
  • An instance of a class that implements the Database.Batchable interface.
  • The job name.
  • The time interval, in minutes, after which the job starts executing.
  • An optional scope value. This parameter specifies the number of records to pass into the execute method. Use this parameter when you have many operations for each record being passed in and are running into governor limits. By limiting the number of records, you are limiting the operations per transaction. This value must be greater than zero. If the start method returns a QueryLocator, the optional scope parameter of System.scheduleBatch can have a maximum value of 2,000. If set to a higher value, Salesforce chunks the records returned by the QueryLocator into smaller batches of up to 2,000 records. If the start method returns an iterable, the scope parameter value has no upper limit. However, if you use a high number, you can run into other limits.
The System.scheduleBatch method returns the scheduled job ID (CronTrigger ID).
This example schedules a batch job to run one minute from now by calling System.scheduleBatch. The example passes this method an instance of a batch class (the reassign variable), a job name, and a time interval of one minute. The optional scope parameter has been omitted. The method returns the scheduled job ID, which is used to query CronTrigger to get the status of the corresponding scheduled job.
01String cronID = System.scheduleBatch(reassign, 'job example'1);
02 
03CronTrigger ct = [SELECT Id, TimesTriggered, NextFireTime
04                FROM CronTrigger WHERE Id = :cronID];
05 
06// TimesTriggered should be 0 because the job hasn't started yet.
07System.assertEquals(0, ct.TimesTriggered);
08System.debug('Next fire time: ' + ct.NextFireTime);
09// For example:
10// Next fire time: 2013-06-03 13:31:23
For more information, see CronTrigger in the Object Reference for Salesforce and Force.com.
Note
Some things to note about System.scheduleBatch:
  • When you call System.scheduleBatch, Salesforce schedules the job for execution at the specified time. Actual execution occurs at or after that time, depending on service availability.
  • The scheduler runs as system—all classes are executed, whether or not the user has permission to execute the class.
  • When the job’s schedule is triggered, the system queues the batch job for processing. If Apex flex queue is enabled in your org, the batch job is added at the end of the flex queue. For more information, see Holding Batch Jobs in the Apex Flex Queue.
  • All scheduled Apex limits apply for batch jobs scheduled using System.scheduleBatch. After the batch job is queued (with a status of Holding or Queued), all batch job limits apply and the job no longer counts toward scheduled Apex limits.
  • After calling this method and before the batch job starts, you can use the returned scheduled job ID to abort the scheduled job using the System.abortJob method.

1 comment:

  1. Great overview of using Batch Apex! Implementing clear coding styles with fonts like FiraCode can really enhance code readability and make working with large data sets much more manageable.

    ReplyDelete

Lightning Inter-Component Communication Patterns

Lightning Inter-Component Communication Patterns If you’re comfortable with how a Lightning Component works and want to build producti...