Batch Apex
Batch Apex is used to run large jobs (thousands or millions of records!) that would exceed normal processing limits.
1) Every transaction starts with a new set of governor limits, which makes it easier to ensure that code stays within the governor execution limits.
2) It allow partial DML, which means if one batch fails to process successfully, all other successful batch transactions aren’t rolled back.
Batch Apex Syntax:
global class BatchClass implements Database.Batchable<sObject> {
global Database.QueryLocator start(Database.BatchableContext bc) {
// collect the batches of records or objects to be passed to execute
}
global void execute(Database.BatchableContext bc, List<P> records){
// process each batch of records
}
global void finish(Database.BatchableContext bc){
// execute any post-processing operations
}
}
To Invoke a Batch Class and get Batch_id:
//1. Create an instance of batch class
MyBatchClass myBatchObject = new MyBatchClass();
//2. Pass instance of batch class into Database.excuteBatch method to get batch_id
Id batchId = Database.executeBatch(myBatchObject);
Id batchId = Database.executeBatch(myBatchObject, 100);
//Use batch_id to To fetch info about processing batch
AsyncApexJob job = [Select Id, Status, JobItemsProcessed, TotalJobItems, NumberOfErrors From AsyncApexJob Where Id = :batchId ];
Using Database.Stateful in Batch Apex
It is used to retain state of execution across transactions.
global class UpdateContactAddresses implements Database.Batchable<sObject>, Database.Stateful {
// instance member to retain state across transactions
global Integer recordsProcessed = 0;
global Database.QueryLocator start(Database.BatchableContext bc) {
return Database.getQueryLocator(
'SELECT ID, BillingStreet, BillingCity, BillingState, ' +
'BillingPostalCode, (SELECT ID, MailingStreet, MailingCity, ' +
'MailingState, MailingPostalCode FROM Contacts) FROM Account ' +
'Where BillingCountry = \'USA\''
);
}
global void execute(Database.BatchableContext bc, List<Account> scope){
// process each batch of records
List<Contact> contacts = new List<Contact>();
for (Account account : scope) {
for (Contact contact : account.contacts) {
contact.MailingStreet = account.BillingStreet;
contact.MailingCity = account.BillingCity;
contact.MailingState = account.BillingState;
contact.MailingPostalCode = account.BillingPostalCode;
// add contact to list to be updated
contacts.add(contact);
// increment the instance member counter
recordsProcessed = recordsProcessed + 1;
}
}
update contacts;
}
global void finish(Database.BatchableContext bc){
System.debug('Records processed===> '+recordsProcessed.);
AsyncApexJob job = [SELECT Id, Status, NumberOfErrors,
JobItemsProcessed,
TotalJobItems, CreatedBy.Email
FROM AsyncApexJob
WHERE Id = :bc.getJobId()];
// call some utility to send email
EmailUtils.sendMessage(a, recordsProcessed);
}
}
Testing Batch Apex
@isTest
private class UpdateContactAddressesTest {
@testSetup
static void setup() {
List<Account> accounts = new List<Account>();
List<Contact> contacts = new List<Contact>();
// insert 10 accounts
for (Integer i=0;i<10;i++) {
accounts.add(new Account(name='Account '+i,
billingcity='New York', billingcountry='USA'));
}
insert accounts;
// find the account just inserted. add contact for each
for (Account account : [select id from account]) {
contacts.add(new Contact(firstname='first',
lastname='last', accountId=account.id));
}
insert contacts;
}
static testmethod void test() {
Test.startTest();
UpdateContactAddresses uca = new UpdateContactAddresses();
Id batchId = Database.executeBatch(uca);
Test.stopTest();
// after the testing stops, assert records were updated properly
System.assertEquals(10, [select count() from contact where MailingCity = 'New York']);
}
}
Abort Running Batch
1) Abort one Apex Batch Job by Job_Id.
Setup -> Monitoring -> Apex Jobs to get Batch Job Id.
Finally run below statement from anonymous block.
//pass JobId to System.abortJob() method
System.abortJob(JobID);
2) Abort bulk Apex Job by Job_Id.
// Loop through jobs located by name that we need to abort
List<CronTrigger> jobsToAbort = [Select Id, CronJobDetail.Name, CronJobDetail.JobType From CronTrigger Where CronJobDetail.Name like 'WorkOrder%'];
for(CronTrigger ct : jobsToAbort){
// abort the job, try/catch because the job might not exist
try {
system.abortJob(ct.id);
} catch (exception e) {
System.debug('Exception Message: '+e.getMessage());
}
}
Batch Apex Consideration
1) Up to 5 queued or active batch jobs are only allowed.
2) A maximum of 50 million records can be returned in the Database.QueryLocator object. If more than 50 million records are returned, the batch job is immediately terminated and marked as Failed
3) If no size is specified as optional scope parameter of Database.executeBatch, Salesforce breaks the records returned by the start method into batches of 200, and then passes each batch to the execute method.
Note: Apex governor limits are reset for each execution of execute.
4) The start, execute, and finish methods can implement up to 10 callouts each
5) The maximum number of batch executions is 250,000 per 24 hours
6) Only one batch Apex job's start method can run at a time in an organization. Batch jobs that haven’t started yet remain in the queue until they're started.
Batch Apex is used to run large jobs (thousands or millions of records!) that would exceed normal processing limits.
1) Every transaction starts with a new set of governor limits, which makes it easier to ensure that code stays within the governor execution limits.
2) It allow partial DML, which means if one batch fails to process successfully, all other successful batch transactions aren’t rolled back.
Batch Apex Syntax:
global class BatchClass implements Database.Batchable<sObject> {
global Database.QueryLocator start(Database.BatchableContext bc) {
// collect the batches of records or objects to be passed to execute
}
global void execute(Database.BatchableContext bc, List<P> records){
// process each batch of records
}
global void finish(Database.BatchableContext bc){
// execute any post-processing operations
}
}
To Invoke a Batch Class and get Batch_id:
//1. Create an instance of batch class
MyBatchClass myBatchObject = new MyBatchClass();
//2. Pass instance of batch class into Database.excuteBatch method to get batch_id
Id batchId = Database.executeBatch(myBatchObject);
Id batchId = Database.executeBatch(myBatchObject, 100);
//Use batch_id to To fetch info about processing batch
AsyncApexJob job = [Select Id, Status, JobItemsProcessed, TotalJobItems, NumberOfErrors From AsyncApexJob Where Id = :batchId ];
Using Database.Stateful in Batch Apex
It is used to retain state of execution across transactions.
global class UpdateContactAddresses implements Database.Batchable<sObject>, Database.Stateful {
// instance member to retain state across transactions
global Integer recordsProcessed = 0;
global Database.QueryLocator start(Database.BatchableContext bc) {
return Database.getQueryLocator(
'SELECT ID, BillingStreet, BillingCity, BillingState, ' +
'BillingPostalCode, (SELECT ID, MailingStreet, MailingCity, ' +
'MailingState, MailingPostalCode FROM Contacts) FROM Account ' +
'Where BillingCountry = \'USA\''
);
}
global void execute(Database.BatchableContext bc, List<Account> scope){
// process each batch of records
List<Contact> contacts = new List<Contact>();
for (Account account : scope) {
for (Contact contact : account.contacts) {
contact.MailingStreet = account.BillingStreet;
contact.MailingCity = account.BillingCity;
contact.MailingState = account.BillingState;
contact.MailingPostalCode = account.BillingPostalCode;
// add contact to list to be updated
contacts.add(contact);
// increment the instance member counter
recordsProcessed = recordsProcessed + 1;
}
}
update contacts;
}
global void finish(Database.BatchableContext bc){
System.debug('Records processed===> '+recordsProcessed.);
AsyncApexJob job = [SELECT Id, Status, NumberOfErrors,
JobItemsProcessed,
TotalJobItems, CreatedBy.Email
FROM AsyncApexJob
WHERE Id = :bc.getJobId()];
// call some utility to send email
EmailUtils.sendMessage(a, recordsProcessed);
}
}
Testing Batch Apex
@isTest
private class UpdateContactAddressesTest {
@testSetup
static void setup() {
List<Account> accounts = new List<Account>();
List<Contact> contacts = new List<Contact>();
// insert 10 accounts
for (Integer i=0;i<10;i++) {
accounts.add(new Account(name='Account '+i,
billingcity='New York', billingcountry='USA'));
}
insert accounts;
// find the account just inserted. add contact for each
for (Account account : [select id from account]) {
contacts.add(new Contact(firstname='first',
lastname='last', accountId=account.id));
}
insert contacts;
}
static testmethod void test() {
Test.startTest();
UpdateContactAddresses uca = new UpdateContactAddresses();
Id batchId = Database.executeBatch(uca);
Test.stopTest();
// after the testing stops, assert records were updated properly
System.assertEquals(10, [select count() from contact where MailingCity = 'New York']);
}
}
Abort Running Batch
1) Abort one Apex Batch Job by Job_Id.
Setup -> Monitoring -> Apex Jobs to get Batch Job Id.
Finally run below statement from anonymous block.
//pass JobId to System.abortJob() method
System.abortJob(JobID);
2) Abort bulk Apex Job by Job_Id.
// Loop through jobs located by name that we need to abort
List<CronTrigger> jobsToAbort = [Select Id, CronJobDetail.Name, CronJobDetail.JobType From CronTrigger Where CronJobDetail.Name like 'WorkOrder%'];
for(CronTrigger ct : jobsToAbort){
// abort the job, try/catch because the job might not exist
try {
system.abortJob(ct.id);
} catch (exception e) {
System.debug('Exception Message: '+e.getMessage());
}
}
Batch Apex Consideration
1) Up to 5 queued or active batch jobs are only allowed.
2) A maximum of 50 million records can be returned in the Database.QueryLocator object. If more than 50 million records are returned, the batch job is immediately terminated and marked as Failed
3) If no size is specified as optional scope parameter of Database.executeBatch, Salesforce breaks the records returned by the start method into batches of 200, and then passes each batch to the execute method.
Note: Apex governor limits are reset for each execution of execute.
4) The start, execute, and finish methods can implement up to 10 callouts each
5) The maximum number of batch executions is 250,000 per 24 hours
6) Only one batch Apex job's start method can run at a time in an organization. Batch jobs that haven’t started yet remain in the queue until they're started.
No comments:
Post a Comment