The post Asynchronous Apex, The Savior from Salesforce Governor Limits appeared first on Salesforce Next Gen.
]]>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:-
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:-
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.
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 }}
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:
Next, we will discuss the 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:
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];
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);
}
}
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());
}
}
Now we will discuss 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.
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:
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. |
Following are the limitations of Apex Scheduler:
Now let’s shift our focus to 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.
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.
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(‘batch@acme.com’);
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=’test@acme.com’;
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){
}
}
Also check the interview questions based on Batch Class
The post Asynchronous Apex, The Savior from Salesforce Governor Limits appeared first on Salesforce Next Gen.
]]>