Adsense

Showing posts with label @future. Show all posts
Showing posts with label @future. Show all posts

November 30, 2019

Queueable Apex - The middle way

The last post was a comparison between batch apex and @future apex. There are some advantage and disadvantage with both of them. When batch and @future needs to meet in between - queueable comes for rescue.

There are a few things that @future did not provide:
  1. @future requires the arguments be primitives, which means reconstructing a structure once the method is called.
  2. Difficult access to job ID. The executeBatch method returns a jobID, while calling an @future job does not give you the ID of the related job.
  3. No chaining - Chaining of batch apex is not allowed.
Q - Why we go for queueable Apex?
A - When the job such as extensive database operations or external Web service callouts is long running and is running asynchronously and you want to monitor the job status. It can be done via queueable apex and adding a job to the ApexJob queue. In this way, your asynchronous Apex job runs in the background in its own thread and doesn’t delay the execution of your main Apex logic.

Queueable jobs are similar to future methods in that they’re both queued for execution, but they provide you with these additional benefits.

Getting an ID for your job: When you submit your job by invoking the System.enqueueJob method, the method returns the ID of the new job. This ID corresponds to the ID of the AsyncApexJob record.
This ID helps you identify your job and monitor its progress, either through the Salesforce user interface in the Apex Jobs page, or programmatically by querying your record from AsyncApexJob.

Using non-primitive types: Your queueable class can contain member variables of non-primitive data types, such as sObjects or custom Apex types.

Chaining Jobs: In queueable you can also chain Jobs from a running job. It is very helpful if some processing needs to be done which depends on the last results.

Example:
This example is an implementation of the Queueable interface. The execute method in this example inserts a new account.

public class QueueableExample implements Queueable {

    public void execute(QueueableContext context) {
        Account acc = new Account(Name='Test Account Neeraj');
        Insert acc;     
    }
}

To add this class as a job on the queue, call this method:
ID jobID = System.enqueueJob(new QueueableExample());

After you submit your queueable class for execution, the job is added to the queue and will be processed when system resources become available. We can monitor the status of our job programmatically by querying AsyncApexJob or through the user interface Setup --> Monitor --> Jobs --> Apex Jobs.

Test class for queueable apex:

@isTest
public class AsyncExecutionExampleTest {
    static testmethod void testAccount() {
     
        Test.startTest();     
        System.enqueueJob(new QueueableExample());
        Test.stopTest();

        Account acct = [SELECT Name FROM Account WHERE Name='Test Account Neeraj' LIMIT 1];
        System.assertEquals('Test Account Neeraj', acct.Name);
    }
}

Few things can be noted here:

  • The execution of a queued job counts against the shared limit for asynchronous Apex method executions.
  • We can add up to 50 jobs to the queue with System.enqueueJob in a single transaction.
  • Use Limits.getQueueableJobs() to check how many queueable jobs have been added in one transaction.
  • No limit is enforced on the depth of chained jobs.
  • We can add only one job from an executing job with System.enqueueJob, that means only child job can exist for parent queueable job.

Read More »

October 06, 2019

@Future vs Batch Apex in salesforce

Future Annotation: 
  1. Future Annotation(@Future) is used to separate methods that are to be executed asynchronously.
  2. If Future Annotation is not used in a web service callout, the thread will wait until the response comes and other processes will not be executed.
  3. Mixed DML Exception can be avoided with the use of @future annotation.
  4. @future annotation - Must be static and return void - Specify (callout=true) to allow callouts.
  5. Parameters passed to this can only be primitive.
  6. Tracking future is difficult as you don't have any jobId to track it.
  7. Future can be used to resolve mixed DML exception.
Example: You cannot insert a setup object and a non-setup object in same context. You'll encounter mixed DML exception. @Future comes for rescue in this situation.
public class MixedDMLFuture {
    public static void useFutureMethod() { 
        //First DML operation- Insertion of non-setup object(Account)
        Account a = new Account(Name='Vydehi Hospital'); 
        insert a; 
        
        // This next operation (insert a user with a role)  can't be mixed with the previous insert unless it is within a future method. 
        /*// Other DML Operation -- commented the code with a reason, if you use the commented code you will get mixed DML exception error
        Profile p = [SELECT Id FROM Profile WHERE Name='Standard User']; 
        UserRole r = [SELECT Id FROM UserRole WHERE Name='COO']; 
        // Create new user with a non-null user role ID 
        User u = new User(alias = 'ranvk', email='dummyMail@gmail',                   
                          emailencodingkey='UTF-8', lastname='niru',languagelocalekey='en_US',     
                          localesidkey='en_US', profileid = p.Id, userroleid = r.Id,  
                          timezonesidkey='America/Los_Angeles',  
                          username='dM@gmail.com'); 
        insert u; */
        //Call future method to insert a user(setup object) with a role. 
        UtilClass.insertUserWithRole( 'dummyMail@gmail.com', 'ranvk', 'dM@gmail.com', 'niru'); 
    } 
}

public class UtilClass { 
      @future 
       public static void insertUserWithRole(String uname, String al, String em, String lname) { 
               Profile p = [SELECT Id FROM Profile WHERE Name='Standard User']; 
               UserRole r = [SELECT Id FROM UserRole WHERE Name='COO']; 
               // Create new user with a non-null user role ID 
               User u = new User(alias = al, email=em, emailencodingkey='UTF-8',   
                              lastname=lname, languagelocalekey='en_US', localesidkey='en_US', 
                              profileid = p.Id, userroleid = r.Id, timezonesidkey='America/Los_Angeles',  
                              username=uname); 
               insert u; 
       } 
}


Batch Apex:
  1. Batch Apex is used to separate tasks that are going to handle more records(complex long running jobs) in background process. 
  2. To avoid hitting governor limits we use Batch Apex for handling bulk records.
  3. It can process up to 50 million records. It can also be scheduled to run at a particular time.
  4. Only 5 concurrent batch can execute simultaneously. It is difficult to track the progress of the execution.
  5. We cannot use @future annotation. As asynchronous call is not allowed from batch apex.


Example: Delete all the account having Rating 'Cold'
global class deleteAccounts implements Database.Batchable{
global Database.QueryLocator start(Database.BatchableContext BC){
string query = 'select id,name,Rating,Owner from Account';
return Database.getQueryLocator(query);
}

global void execute(Database.BatchableContext BC,List scope){
List <Account> lstAccount = new list<Account>();
for(Sobject s : scope){
Account a = new Account();
if(s.Rating=='Cold'){
lstAccount.add(a);
}
}
Delete lstAccount;
}

global void finish(Database.BatchableContext BC){
//Send an email to the User after your batch completes
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {'dummyemail@gmail.com'};
mail.setToAddresses(toAddresses);
mail.setSubject('Apex Batch Job is completed');
mail.setPlainTextBody('The batch Apex job processed ');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}

Read More »