BATCH APEX :
Why do we use
Batches?
If we have a use case to process millions of records, it
would be difficult to do this manually as well as in a synchronous context (time
limit is 10 seconds) so we use batches to process bulk data or records
together, with a new set of Governor limits per transaction.
Why to use Batch
class as we already having data loader to process the bulk data.?
if and only if the data needs to be
updated is static or predefined or which can be done through excel.
We will choose batch class if we have to
perform some custom calculations at run time or if you want to run some complex
logic which can't be driven by excel sheets in those cases we have to go with
batch classes.
For Examples:
• Do some relationship queries to update
the data.
• Make a call out to get some information related to each record.
What interface
will you use for batch apex?
It is Database.Batchable interface.
What did you
mean by “a new set of governor limits per transaction”?
Batch Jobs can be operated on any size of records, with a
maximum of 200 records per batch. Each batch is a transaction. The Apex
governor limits are reset for each transaction.
Can you write a
batch class blueprint?
global class batch implements Database.Batchable <sObject> {
global (Database.QueryLocator or
Iterable<sobject>)
start(Database.BatchableContext bc) {
//query on object;
//return Database.getQueryLocator(query);
}
global void execute(Database.batchableContext bc, List <SObject>
scope) {
//some processing.
}
global void finish(Database.BatchableContext bc) {
//job such as sending email or calling another
batch class
}
}
What is the
difference between Database.QueryLocator & Iterable<sobject> used in
batch apex?
In Database.QueryLocator, the governor limit for the total number of records
retrieved by SOQL queries is bypassed and you can query up to 50 million
records.
In Iterable<sobject>, we can create a custom scope for processing, which
would be not possible to create using SOQL where clauses. The governor limit
for the total number of records retrieved by SOQL queries is still enforced.
If the code accesses external objects and is used in batch
Apex, use Iterable<sObject> else Database.QueryLocator.
Can you explain
more about iterable interface. What you mean by custom scope?
When you have a use case in which SQOL
can’t be constructed, we can use custom code to create the scope of a batch.
For example, A batch accepts account
records, where each account is having more than 2 contacts and each contact’s
mailing address should not be the same.
Now, you can’t create a SOQL for this use
case, so use the iterable interface, and create a list of accounts using
queries and loops, and return the final processed account list, to the batch.
This final list is called a custom scope.
If We use Itereable<sObject>, will We be able to
process Batches in a specific order?
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. So even if you do ORDER BY, there is no guarantee
of processing in the same order.
In a batch
context, can I process Data in a specific order?
Yes, You can order the scope of that batch, however, you want
and process it.
Can I query
related records using Database.QueryLocator ?
Yes, You can do subquery for related records, but with a
relationship subquery, the batch job processing becomes slower. A better
strategy is to perform the subquery separately, from within the execute method,
which allows the batch job to run using the faster.
Can I Use FOR
UPDATE in SOQL using Database.QueryLocator?
No, We can’t. It will through an exception stating that
“Locking is implied for each batch execution and therefore FOR UPDATE should
not be specified”.
The reason is, If we query the entire database of an
org using SELECT.
FOR UPDATE, we would lock the entire database as long as the batch was active.
What is the
state of batch apex?
Batch Apex is typically stateless. Each execution of a batch
Apex job is considered a discrete transaction.
For example, a batch Apex job that contains
1,000 records and uses the default batch size is considered five transactions
of 200 records each.
Let’s say Record
A has to be processed before Record B, but Record B came in the first Batch and
Record A came in the second batch. The batch picks records which are
unprocessed every time it runs. How will you control the processing Order?
The Processing order can’t be controlled, but we can
bypass the Record B processing before Record A. We can implement Database.STATEFUL and use one class variable to track whether
Record A has processed or not. If not processed and Record B has come, don’t process
Record B. After all the execution completes, Record A has already been
processed so Run the batch again, to process Record B.
What is
Database.Stateful?
Database.Stateful is a interface helps in
maintaining state across transactions. When using Database.Stateful, only instance member variables retain their values
between transactions.
Static member variables don’t retain their values and are reset between
transactions.
Maintaining state is useful for counting
or summarizing records as they’re processed.
For example, we’ll be updating contact records in our batch job
and want to keep track of the total records affected so we can include it in
the notification email.
Is there any
other interface that can be implemented by a Batch apex?
Database.AllowsCallouts is another Interface,
which is implemented to make HTTP callouts through Batch.
How to monitor
Batch job?
Go to Setup --->Apex Job
What is the
Limit of Size of scope in a batch?
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.
If a batch is
having 200 records and 1 record fails what will happen?
If any record fails all 200 record will fail but next batch
will get executed.
How to calculate
the batch size if we are making any call out from the batch class execute
method?
Basically in salesforce we have
limitation of 100 call outs for a transaction. When it comes to batch class
each execute method call will be considered as one transaction. So, in this
case your batch size must be calculated in such way
Batch size = (No of callouts allowed for
single transaction /total number of call outs for each record) - 1;
Batch size = (100 /total number of call
outs for each record) - 1
How many times
the execute method will be executed to process the 1236 records.
it depends on your batch size what you
have configured at the time of calling the batch class from schedule class.
Execution method count = Total No Of
Records/Batch Size (Any decimal ceil it to upper value)
If you haven't set any batch size then :
|
|
1236 |
= 6.18 |
= 7 times execute method will be called |
|
200 |
Can we call the
batch into another batch apex?
Yes, we can call from the finish method.
Can we
call batch apex into another batch in execute method?
Only in batch class finish method, We can
call another batch class. If you will call another batch class from batch class
execute and start method, then Salesforce will throw below runtime error.
System.AsyncException: Database.executeBatch cannot be called from a batch start, batch
execute, or future method.
Why to call only
from the finish method why not from execute?
Because the execute method will gets
invoked multiple times based on the volume of the records and batch size. So,
if your calling it from execute method then the chaining class will get called
multiple times which is not an suggested way of doing.
We can also use the Queueable Apex for
chaining of the jobs.
Let’s say, we
have run an apex batch to process 1000 records, and It is running with batch
size 200. Now, while doing DML on 398th record, an error occurred, What will
happen in that case?
In batches, If the first transaction
succeeds but the second fails, the database updates made in the first
transaction are not rolled back.
Since the batch size is 200, so the first
batch will be processed completely and all data will be committed to DB. In
seconds batch, if we are committing records using normal DML statements
like insert, update than the whole batch will
be rollbacked. So records 201 to 400 will not be processed.
If we use the Database DML operations
like Database.insert with AllOrNone as false,
then partial commit can happen and only 398th record will not be processed in
that batch and total 199 records will be processed. Also, the other batch
execution will not gonna be hampered.
Can I call
any method from Batch Apex?
Methods declared as future can’t be called from a batch Apex class.
Is there is any way through which we can call future method from
batch apex?
As we know that a webservice can be called from batch
class and webservice can call @future method. So in your batch class call web service
and which can call your @future method. Also, you can call future methods from
the finish method in the batch class.
How many can concurrent batch jobs be added to the queue?
At most, there can be 5 batch jobs queued at a time.
Can we call the
batch apex from triggers in salesforce?
Yes, it is possible. We can call a batch apex from trigger
but we should always keep in mind that we should not call batch apex from
trigger each time as this will exceeds the governor limit this is because of
the reason that we can only have 5 apex jobs queued or executing at a time.
Can we call
webservice callout from batch apex?
To make a Webservice callout in batch Apex, we have to implement Database.AllowsCallouts interface.
How many times start, execute, finish methods will execute in
batch apex?
Start method, finish method one time, execute method it
depends on requirement. Based on the batch size and data retrieved in Start
method.
What is the
Batch executions limit per day?
The maximum number of batch executions is 250,000 per 24
hours.
How can we
track the status of the current running batch job?
The job Id returned by the batchable context variable
helps us in finding the status of a batch through AsyncApexJob object.
For
example,
global void finish(Database.BatchableContext info){
// Get the ID of the AsyncApexJob representing
this batch job
// from Database.BatchableContext.
// Query the AsyncApexJob object to retrieve
the current job's information.
AsyncApexJob a = [SELECT Id, Status,
NumberOfErrors, JobItemsProcessed,
TotalJobItems, CreatedBy.Email FROM
AsyncApexJob WHERE Id = :info.getJobId()];
// Send an email to the Apex job's submitter
notifying of job completion.
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {a.CreatedBy.Email};
mail.setToAddresses(toAddresses);
mail.setSubject('Account and contact update' + a.Status);
mail.setPlainTextBody
('The batch Apex job processed ' + a.TotalJobItems +
' batches with '+ a.NumberOfErrors + '
failures.'+successRecord+'successRecordids: '+ 'failRecordids: '+ failRecord);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
How can you stop a Batch job?
The Database.executeBatch and System.scheduleBatch method returns an
ID that can be used in System.abortJob method.
How to stop all
the running batches related to a particular batch classes before scheduling the
same batch class from the schedule class.
global class CaseCreationonSchedular implements Schedulable
{
global void execute(SchedulableContext SC)
{
for(AsyncApexJob ap: [SELECT Id, ApexClass.Name,createddate,
JobType, Status, JobItemsProcessed, MethodName, ParentJobId
FROM AsyncApexJob
Where ParentJobId!=Null
AND JobType IN('BatchApex','BatchApexWorker')
And ApexClass.Name='YourBatchClassName'
And Status NOT IN('Completed','Aborted')])
{
System.abortJob(ap.ParentJobId);
}
YourBatchClassName cls = new YourBatchClassName();
DataBase.executeBatch(cls);
}
}
What is Apex
Flex Queue?
At a time salesforce allows 5 batches to
be running or to be in queued state. So, if you have consumed all these 5
limits and if system has received one or more batch execution request all these
waiting batch will be stored in this Apex Flex Queue.
The maximum number of batch classes
allowed in Apex Flex Queue for execution is 100.
Let’s say, I
have 150 Batch jobs to execute, Will I be able to queue them in one go?
Once you run Database.executeBatch, the Batch jobs will be placed in the Apex flex queue
and its status becomes Holding. 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. So atmost 100 jobs can be added in one go.
Also, if Apex flex queue is not enabled,
the Job status becomes Queued, Since the concurrent limit of the queued or active batch
is 5, so atmost 5 batch jobs can be added in one go.
Can I change the
order of already queued Batch Jobs?
Only jobs having status as Holding can be moved. It
can be done through UI of Apex Flex queue or we can use Apex Flex Queue
Methods.
Boolean isSuccess =
System.FlexQueue.moveBeforeJob(jobToMoveId, jobInQueueId);
How Can I schedule a Batch Apex?
Through System.scheduleBatch Method, we can schedule batch for once at
a future time. This method returns the scheduled job ID also called CronTrigger ID.
String cronID = System.scheduleBatch(reassign,
'job example', 1);
CronTrigger ct = [SELECT Id, TimesTriggered,
NextFireTime
FROM CronTrigger WHERE Id = :cronID];
Is it possible
to do Synchronous Web service callouts from scheduled apex?
No, Synchronous Web service callouts are not supported by
scheduled Apex. However, if your scheduled Apex executes a batch job, callouts
are supported by the batch class.
Can we call the
scheduler from the future method?
Yes..!! We can call the scheduler from the future method.
Can we modify
the scheduler class or classes referenced by this scheduler class if any
scheduled job is pending?
No, If there are one or more active scheduled jobs for an
Apex class, you cannot update the class or any classes referenced by this class
through the Salesforce user interface.
Can I call
Queueable from a batch?
Yes, But you’re limited to just one System.enqueueJob call per execute
in the Database.Batchable class. Salesforce
has imposed this limitation to prevent explosive execution.
How Can I Test a
Batch Apex?
We can test it by calling the Batch job
between Test.startTest() and Test.stopTest(). Using the Test methods startTest and stopTest around
the executeBatch method to ensure that it finishes before continuing your test.
All asynchronous calls made after the startTest method are
collected by the system. When stopTest is executed, all
asynchronous processes are run synchronously.
Also we can test only one execution of
the execute method. So we need to set the scope as per the governor limits.
How many records
we can insert while testing Batch Apex?
We have to make sure that the number of records
inserted is less than or equal to the batch size of 200 because test methods
can execute only one batch. We must also ensure that the Iterable returned by
the start method matches the batch size.
Write a Batch
apex class to automatically deactivate users when the user's Last Login Date is
greater than 30 days.
global class batchDeactivateUsers implements Database.Batchable<sobject> {
global Database.QueryLocator start(Database.BatchableContext bc){
string query = 'SELECT Name, isActive,
LastLoginDate FROM User WHERE LastLoginDate < LAST_N_DAYS:30';
return database.getQueryLocator(query);
}
global void execute(Database.BatchableContext bc, List<user> users){
List<user> userlist = new List<user>();
for(User u : users){
u.IsActive = false;
userlist.add(u);
}
update userlist;
}
global void finish(Database.BatchableContext bc){
}
}
Update account
description, number of employees, contact last name using batch apex. Get the
failure record ids in the email. Also, schedule the job for every Monday.
global class batchUpdateAccountsContacts implements Database.Batchable <sObject>,Database.Stateful,Schedulable
{
global batchUpdateAccountsContacts(){
}
Set<id> successRecord = new Set<id>();
Set<id> failRecord = new Set<id>();
global Database.QueryLocator
start(Database.BatchableContext info){
String SOQL='Select id, name,
NumberOfEmployees, description,(select id, name from contacts) from Account';
return Database.getQueryLocator(SOQL);
}
global void execute(Database.BatchableContext info, List<account>
scope){
List<account> accsToUpdate = new List<account>();
List<contact> contUpdate = new List<contact>();
for(Account a : scope)
{
a.description ='Welcome to Learnfrenzy - Best
Place to Learn';
a.NumberOfEmployees = 70;
accsToUpdate.add(a);
for (Contact c:a.contacts){
c.lastname = 'test+a';
contUpdate.add(c);
}
}
Database.SaveResult[] srList =
Database.update(accsToUpdate, false);
Database.SaveResult[] srList1 =
Database.update(contUpdate, false);
for (Database.SaveResult sr : srList) {
if (sr.isSuccess()) {
// Operation was successful, so get the ID of
the record that was processed
successRecord.add(sr.getId());
}
else {
for(Database.Error err : sr.getErrors()) {
}
failRecord.add(sr.getId());
}
}
for (Database.SaveResult sr : srList1) {
if (sr.isSuccess()) {
successRecord.add(sr.getId());
}
else {
for(Database.Error err : sr.getErrors()) {
}
failRecord.add(sr.getId());
}
}
}
global void finish(Database.BatchableContext info){
// Get the ID of the AsyncApexJob representing
this batch job
// from Database.BatchableContext.
// Query the AsyncApexJob object to retrieve
the current job's information.
AsyncApexJob a = [SELECT Id, Status,
NumberOfErrors, JobItemsProcessed,
TotalJobItems, CreatedBy.Email FROM
AsyncApexJob WHERE Id = :info.getJobId()];
// Send an email to the Apex job's submitter
notifying of job completion.
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {a.CreatedBy.Email};
mail.setToAddresses(toAddresses);
mail.setSubject('Account and contact update' + a.Status);
mail.setPlainTextBody
('The batch Apex job processed ' + a.TotalJobItems +
' batches with '+ a.NumberOfErrors + '
failures.'+successRecord+'successRecordids: '+ 'failRecordids: '+ failRecord);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
global void execute(SchedulableContext SC){
database.executeBatch(new batchUpdateAccountsContacts(),100);
//for cron expression
// String cronexpression = ‘0 0 0 ? * * *’
// System.schedule(‘Testing’, cronexpression,
testobj);
}
}
database.executeBatch(new batchUpdateAccountsContacts(),100);
No comments:
Post a Comment