Asynchronous Apex, The Savior from Salesforce Governor Limits
Asynchronous Apex, The Savior from Salesforce Governor Limits
Asynchronous Apex, we all know how sometimes Salesforce Governor Limit can haunt us at times. With the limited amount of resource available due to the multi tenant architecture, we have to restrict our self with the optimum usage of the resources. But what if we want to use the platform to its maximum limit, what if we want to do the process on huge volume of data.
To overcome the above-mentioned crisis, Salesforce Apex has provided us with the feature of Asynchronous Apex. To start with Asynchronous Apex provides us with the double governor limits in most of the cases and in some, we can perform a bulk operation on records up to 50 million.
There are lots of benefits of using Asynchronous Apex, but we are supposed to choose which Asynchronous apex would be the best way to reach our business goal.
Image Source: https://developer.salesforce.com/page/Asynchronous_Processing_in_Force_com
How Asynchronous calls are handled by Salesforce’s Queue store and is then distributed to the application servers.
There are 4 Asynchronous Apex features their name and use cases are mentioned below:-
- Future Methods: it is a basic asynchronous feature, we imply this method when we want to prevent any delay in the transaction or when we make a web call out or when we want to prevent the mixed DML error
- Batch Apex: To do bulk processing of records or for the jobs that require larger query result for example processes like Database maintenance jobs.
- Schedule Apex: This feature is used to schedule the invocation of an apex class at a specific time, this can be a recurring event or a one-time task.
- Queueable Apex: When one task is dependent on completion of another task we make use of this asynchronous feature, Also job chaining and complex type of jobs are achieved using this feature
Image Source: https://developer.salesforce.com/page/Asynchronous_Processing_in_Force_com
The above Image is depicting the Process-type(future, batch, and bulk API) wise distribution of the asynchronous processes which are then distributed to different application servers.
Now we will discuss each of these features in detail:-
Asynchronous Apex: Future Method
It is a method which runs on a separate thread in the background. It does not impact the performance of a running transaction as it carried out in a different context. We use this method for the execution of long running operation such as a web call out where we are not sure when the response will come or whether a response will come or not.
This is not the only use case of the future method we also use them to isolate DML statement because there is a possibility that when two DML operation is performed over different sObject then we might get a mixed DML operation error. Future methods help us in preventing this error.
Image: Depicting the difference in thread processing between apex normal transaction and in future method
The specialty of the Future method is that it executes when the resources are available and does not out overhead on the server. This is the reason that execution of the code does not have to wait for the completion of a long running operation and also we get higher Governor limits when we use Asynchronous Apex.
Simple syntax of the future method is mentioned below:
Global class ClassNameOfFutureMethod
{
@Future
Public static void FuturemethoName()
{
ß Code to be executed à
}
}
Some consideration before we start implementing the future method is that it should be declared as a static method and the only return type it can have is void. Secondly, the parameter defined for the future method must be primitive i.e. no salesforce sObject can be passed as a parameter to the future method. The reason an sObject is not passed in the future method is that there is a possibility that the sent sObject might change between the time the future method is executed.
To interact future method with the sObject that already exists in the database, we can pass the ID of the object instead and then fetch the latest version of the record in the method itself and then perform the task, as shown below.
global class ClassNameOfFutureMethod
{
@future
public static void FuturemethoName (List<ID> rIds)
{
// We can get the records based on the list of Ids
List<custObj> obj = [SELECT Name FROM custObj WHERE Id IN : rIds];
// We can Process records after fetching the records
}
}
Below is a skeletal code of a future method that interacts with an external web service. For this we have to add an extra annotation to the method to make the platform aware that this method will interact with an external service, as shown below
global class ClassNameOfFutureMethod
{
@future(callout=true)
public static void FuturemethoName (List<ID> rIds)
{
// We can get the records based on the list of Ids
List<custObj> obj = [SELECT Name FROM custObj WHERE Id IN : rIds];
// We can Process records after fetching the records
}
}
Future methods are invoked as any other method in the apex, but a Future method cannot invoke another future method. There are certain limitations of the future methods in addition to the above-mentioned limitation which are given below:
No more than 50 methods with Future annotation can be called in a single apex invocation.
Maximum 250000 invocation is allowed per rolling 24-hours or number of licenses multiplied by 200 whichever is the greatest is the limit of the invocation. This limit is for the entire organization and is shared with the entire Asynchronous apex, i.e. Batch Apex, Queueable Apex and scheduled Apex.
Testing Future Methods
Since Future method is called in different context then the running thread, it has to be tested in a different way than the normal. To make them run in the same context we make use of startTest() and stopTest() code block. All asynchronous method written after the startTest are collected by the system and are executed synchronously after the stopTest method is called, as shown below.
@isTestprivate class ClassNameOfFutureMethodTest { @isTest static void test1() { Test.startTest(); ClassNameOfFutureMethod.FuturemethoName (); Test.stopTest(); } // Verify the result with help of system.assertEquals }}
Best practice and performance for Future method
Salesforce implements a queue based framework for the handling of the asynchronous processes, the queue is implied to balance the load of request across organizations, following are the best practice for the future methods:
- Ensure fast execution of the of the future methods by tuning the query used in the method, the longer the future method takes to complete the execution the more delay occurs for the requests in the queue.
- Testing the future method to the maximum numbers of the result expected to handle, this will help in determining the delay
- Use batch apex if the number future method invocation is reasonably large. Avoid using a large number of future methods.
Next, we will discuss the Queueable Apex
Asynchronous Apex: Queueable Apex
Queueable Apex is also a way of running Apex jobs asynchronously and to make a class Queueable we need to implement an interface i.e. Queueable interface. With the help of this interface, we can queue jobs and also monitor them, this is an enhanced way of running the asynchronous process as compared to the future method.
Queueable jobs are similar to the future method as both are queued before the execution and get executed only after the resources are available, but the extra feature it offers is below:
- An id is generated when the job is queued, with help of this Id one can monitor the progress of the job, from Salesforce UI or programmatically.
- Non-primitive types are also allowed in these jobs, they can be accessed when the job is executed.
- Chaining of the job is possible in Queueable apex, but it can call only chain one Queueable job
Queueable jobs implements the Queueable interface, in this interface we have an execute method which has return type of void and take QueueableContext as a parameter. Below is an example of implementation of the Apex Queueable job:
public class QueueableClass implements Queueable {
public void execute(QueueableContext context) {
contact con = new contact(lastName=’Datta’,Phone=’9999999999′);
insert con;
}
}
In order to add this class to the queue list, we need to make use of SystemEnqueueJob, these methods return an Id. With help of this Id, we can monitor its progress and check its status.
ID queuejobID = System.enqueueJob(new QueueableClass());
AsyncApexJob queuejobInfo = [SELECT Status,NumberOfErrors FROM AsyncApexJob WHERE Id=: queuejobID];
Testing Queueable Jobs
As we know that Queueable is an asynchronous job, therefore to test these classes we have to make use of the startTest and StopTest methods, where all the asynchronous method runs synchronously. Below is an example of the Queueable job and the way to test it.
@isTest
public class QueueableClass Test {
static testmethod void test1() {
Test.startTest();
System.enqueueJob(new AsyncExecutionExample());
Test.stopTest();
Contact con = [SELECT lastName,Phone FROM Contact WHERE lastName =’Datta’ LIMIT 1];
System.assertNotEquals(null, con);
System.assertEquals(‘9999999999’, con.Phone);
}
}
Chaining the Jobs
There is a possibility that we want to perform a certain task after the completion of another job. As discussed before, we can call another Queueable Job from inside of a running queueable job. To do this we need to add another job to the queue in the execute method of the presently running job. We achieve this as shown below.
public class QueueableClass implements Queueable {
public void execute(QueueableContext context) {
contact con = new contact(lastName=’Datta’,Phone=’9999999999′);
insert con;
System.enqueueJob(new anotherQueueableJobClass());
}
}
Limitations of Queueable Jobs
- 50 jobs can be added to the queue with System.enqueueJob() method in a single transaction
- Maximum depth of chain job is 5 i.e. 4 child jobs and initial parent job for Developer and Trail organizations but there is no limit in other editions
- Only one job can be chained at a time, i.e. only one child job from the same Queueable job.
Now we will discuss Apex Scheduler
Asynchronous Apex: Apex Scheduler
To make a class invocable at a specific time, first, we need to implement Schedulable interface in the class and then schedule it either from Salesforce UI or from the system.schedule method.
Implementing the Interface schedulable
To invoke a class on a regular basis we first need to implement the Schedulable interface, which like Queueable apex has an execute method. The scheduler run as system and user permission has no significance in executing the class.
As mentioned above, while implementing schedulable interface we need to implement the execute method of the interface which is a global method and takes schedulableContext as an argument, its syntax is given below.
global void execute(SchedulableContext sc){}
This method is used to instantiate the class we want to schedule, as shown below.
global class MyScheduleClass implements Schedulable {
global void execute(SchedulableContext SC) {
Class2beSchedule M = new Class2beSchedule ();
}
}
The next method is used to schedule the class it is called system.schedule, as shown below.
MyScheduleClass m = new MyScheduleClass ();
String CronExpression = ’20 30 8 10 2 ?’;
String SchedulejobID = system.schedule(‘My Job’, CronExpression, m);
The schedulable class can also be used to Schedule a batch class, as shown below.
global class MyScheduleClass implements Schedulable {
global void execute(SchedulableContext SC) {
batchclass M = new batchclass ();
database.executeBatch(M);
}
}
Batch can also be schedule using the method system.schedulebatch, about this we will study in detail in later section.
Once the job is scheduled we can keep track of it with the help of schedulableContext, with help of its getTriggerID we can retrieve the Id of the scheduled job and we can query the CronTrigger Object and monitor the progress of the job.
To schedule a class we discussed that there are two ways:
- From system UI
- Using System.Schedule method
The difference between the two ways is that in the system.schedule method we can also specify the minutes and seconds as well but using the UI we can just mention the hour of the day.
Schematics of how to schedule a class from UI
Step 1:
Step 2: To schedule weekly
To Schedule Monthly
Let’s discuss how to create a cron expression:
Basic syntax of cron expression is
S M H DOM Mon DOW Yr
S- Seconds
M- Minutes
H- Hour
DOM- Day_of_month
Mon- month
DOW-Day_of_week
Yr -Year
Then there are some special characters which are used in conjunction with the values like ‘*’, ‘?’, “,”,’-‘
Some sample cron Expressions are mentioned below:
Expression | Description |
0 0 13 * * ? | Class runs every day at 1 PM. |
0 0 22 ? * 6L | Class runs the last Friday of every month at 10 PM. |
0 0 10 ? * MON-FRI | Class runs Monday through Friday at 10 AM. |
0 0 20 * * ? 2010 | Class runs every day at 8 PM during the year 2010. |
Limitation of Apex Scheduler
Following are the limitations of Apex Scheduler:
-
- We can have only 100 apex scheduled jobs at one time in a particular Organization which can be checked and counted at scheduled jobs page in sSalesforce
- They also count against the shared limit for the Asynchronous Apex i.e. 250000 for a rolling 24-hours period.
- Extreme care has to be taken if the job is getting scheduled via Apex Trigger
- Synchronous Web service callouts are not supported by the schedule Apex, to make call out we have to make use of the Asynchronous call out, however, a batch can job can be scheduled and callouts are supported from the batch
- If a scheduled job is supposed to run during the maintenance downtime will be scheduled to execute after the maintenance work is completed.
Now let’s shift our focus to batch class.
Asynchronous Apex: Batch Class
Salesforce Governor limits us to build a long running process like data cleansing or data archiving, where records more than 50000 are being processed at one time. To fulfill this requirement Salesforce has to introduce the batch Apex, a batch job makes smaller chunks of the data which is known as batch size and then asynchronously work on each batch in a separate thread and therefore not hitting the governor limit.
ImageSource: https://i.stack.imgur.com/7mHOq.png How batch works
A batch job can be invoked at runtime programmatically using apex and it can also be scheduled using a scheduled job as discussed above.
Using batch Apex
A Class to be executed as a Batch has to implement the batchable interface. In this interface, we have to implement three methods, i.e Start, execute and finish methods.
Image source: http://4.bp.blogspot.com/-Cug5KaAx5Q4/UkjTViCbSnI/AAAAAAAAAFI/r4ayS5iarrw/s1600/marketing-process-distribute1%5B2%5D.gif Schematic of a Batch Class
To collect the records on which we have to perform the bulk processing tasks are collected in this method, this method returns an iterable or a Database.querylocator, both of the return types have their use cases but mostly Database.querylocator is used.
When a simple query is used to generate the collections of record, we should use database.querylocator. This object by passes the Salesforce governor limit of 50000 records and can return up to 50 million records in an org.
Iterable is created only when we have to create a complex scope or collection of records, Iterable is limited to 50000 records only.
The syntax of the start method is as below:
global (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc ) {}
After the collections of record is gathered the execute method is then next executed. This method is called for each batch, it takes a reference to database.BatchableContext object and a list of sObject. Batches are normally executed in the order they are received, but their execution order is not guaranteed.
The syntax of Execute method is as below:
global void execute(Database.BatchableContext BC, list<P>){}
Once all the batches are executed, then the last method Finish is called. This method takes the batchable context as a parameter and is used to perform post processing task like sending an email.
Syntax of Finish method is as below:
global void finish(Database.BatchableContext BC){}
Each batch is considered as a separate transaction and they avail fresh set of apex governor limit, i.e. if a batch of 500 records are being processed with scope of 50 then 10 batches are going to be executed separately and the governor limits will reset for each batch.
Examples of batch Classes
global class UpdateAccountFields implements Database.Batchable<sObject>{
global final String Query;
global final String Entity;
global final String Field;
global final String Value;
global UpdateAccountFields(String q, String e, String f, String v){
Query=q; Entity=e; Field=f;Value=v;
}
global Database.QueryLocator start(Database.BatchableContext BC){
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC,
List<sObject> scope){
for(Sobject s : scope){s.put(Field,Value);
} update scope;
}
global void finish(Database.BatchableContext BC){
}
}
To call this batch class we need to us the following code:
String q = ‘SELECT Industry FROM Account LIMIT 10’;
String e = ‘Account’;
String f = ‘Industry’;
String v = ‘Consulting’;
Id batchInstanceId = Database.executeBatch(new UpdateAccountFields(q,e,f,v), 5);
The following code is to re assign the account owner to a new one.
global class OwnerReassignment implements Database.Batchable<sObject>{
String query;
String email;
Id toUserId;
Id fromUserId;
global Database.querylocator start(Database.BatchableContext BC){
return Database.getQueryLocator(query);}
global void execute(Database.BatchableContext BC, List<sObject> scope){
List<Account> accns = new List<Account>();
for(sObject s : scope){Account a = (Account)s;
if(a.OwnerId==fromUserId){
a.OwnerId=toUserId;
accns.add(a);
}
}
update accns;
}
global void finish(Database.BatchableContext BC){
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(new String[] {email});
mail.setReplyTo(‘[email protected]’);
mail.setSenderDisplayName(‘Batch Processing’);
mail.setSubject(‘Batch Process Completed’);
mail.setPlainTextBody(‘Batch Process has completed’);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
To call the owners reassign batch class we need to use the following code:
OwnerReassignment A = new OwnerReassignment();
A.query = ‘SELECT Id, Name, Ownerid FROM Account ‘ +
‘WHERE ownerid=\” + u.id + ‘\”;
A.email=’[email protected]’;
A.fromUserId = u;
A.toUserId = u2;
ID id = Database.executeBatch(A);
To Allow Callout in the batch class we need it to implement another interface i.e. Database.AllowsCallouts
Each batch execution is a different transaction and one transaction is unaware about the status and progress of the other transaction. The entire batch executed are asynchronous process and do not have a state after they have finished executing. To maintain the state and pass a value from one batch to another we need to specify another interface while defining the class, i.e. Database.Stateful.
Below is the code to aggregate the total of amount of opportunity.
global class SummarizeAccountTotal implements
Database.Batchable<sObject>, Database.Stateful{
global final String Query;
global integer Summary;
global SummarizeAccountTotal(String q){Query=q;
Summary = 0;
}
global Database.QueryLocator start(Database.BatchableContext BC){
return Database.getQueryLocator(query);
}
global void execute(
Database.BatchableContext BC,
List<sObject> scope){
for(sObject s : scope){
Summary = Integer.valueOf(s.get(‘total__c’))+Summary;
}
}
global void finish(Database.BatchableContext BC){
}
}
Batch Apex governor Limits
- 5 batch jobs can run concurrently at a time in a given organization
- Upto 100 jobs can be held in the Apex Flex queue.
- Maximum number of batch that can be executed is 250000 per rolling 24 hour periods. This limit is shared among the all asynchronous process like Future, Queueable and schedulable.
- Maximum of 50 mil records can be returned by Database.querylocator and if more records are returned then the job is terminated immediately.
- Maximum limit of a batch size is 2000, if higher value is set then the records are chunked into size of 2000, in case of iterable there is no upper limit.
- A batch can implement a maximum of 100 callout and the call can be from any method i.e. start, execute and finish
Batch Apex Best Practice
- Take extreme precaution when scheduling a batch from a Trigger, as it can breach platform limit very easily.
- While testing only one batch of apex can be tested using test.starttest() and Test.StopTest methods().
- Use Database.Stateful only if you want to share instance member variable value across the whole job, otherwise it will impact the efficiency of the overall job performance.
- Future methods are not allowed in a batch class, it cannot execute a future method
- Another Batch job can be called from the finish method of the Batch class, it is called chaining batch job.
Also check the interview questions based on Batch Class
[…] Asynchronous Apex […]
[…] Asynchronous Apex, Batch Apex, Future method, Queuable and Schedule. Asynchronous Apex, we all know how sometimes Salesforce Governor Limit can haunt us at times. With the limited amount of resource available due to the multi tenant architecture, we have to restrict our self with the optimum usage of the resources. But what if we want to use the platform to its maximum limit, what if we want to do the process on huge volume of data. […]
Very nice article sir. The concept of Async apex is now clear for me. Thank you so much.
[…] Master to Mastere) Both b & c Q.5. Q.6. Q7. Q.8. 9. Q.10. *CCC selected Q.11. Q.12. Q.13. Get { Asynchronous Apex, Batch Apex, Future method, Queuable and Schedule. Asynchronous Apex, we all know how sometimes Salesforce Governor Limit can haunt us at times. With […]