Thursday, 27 February 2014

Batchable and Schedulable APEX are mutually exclusive but together they are just awesome



Batchable and Schedulable APEX are mutually exclusive; you can have one without the other, but together they are just that much more awesome.

Batch Apex is exposed as an interface that must be implemented by the developer. Batch jobs can be programmatically invoked at runtime using Apex.

Need of Batch Apex

As you all might know about the salesforce governor limits on its data. When you want to fetch thousands of records or fire DML on thousands of rows on objects it is very complex in Salesforce and it does not allow you to operate on more than certain number of records which satisfies the Governor limits. But for medium to large enterprises, it is essential to manage thousands of records every day. Adding/editing/deleting them when needed.
Salesforce has come up with a powerful concept called Batch Apex. Batch Apex allows you to handle more number of records and manipulate them by using a specific syntax.

Let's understand it through one of its implications in S2E instance.

Requirement: Write a Batch Apex to schedule populating Offer Code from Campaign object to Offer Code on Opportunity object.

Enumerating the whole concept/process into the following categories:

1.     Schedule Apex:

Schedule an Apex class that implements the 'Schedulable' interface to be automatically executed on a weekly or monthly interval.

Some code snippets

global class scheduleOfferCodeUpdateOnOpportunity implements Schedulable{


    global void execute(SchedulableContext SC){
        BatchUpdateOfferCodeOnOppty oBatchUpdateOfferCodeOnOppty = new BatchUpdateOfferCodeOnOppty();
        Database.executeBatch(oBatchUpdateOfferCodeOnOppty);
    }

}

Note: You can use the Database.executeBatch method to programmatically begin a batch job.

2.     Call Batch Apex to run the process:

Write an Apex class that implements Database.Batchable, Database.Stateful to start(getQueryLocator), execute(update list of Object records) and finish(Async Apex job and send an email) the Batch job.

  •   The start method is called at the beginning of a batch Apex job.
    •    Use the start method to collect the records or objects to be passed to the interface method execute.
            This method returns either a Database.QueryLocator object or an iterable that contains the records or objects being passed into the job.


  • The execute method is called for each batch of records passed to the method.
    • Use this method to do all required processing for each chunk of data.
    • This method takes the following:
      • A reference to the Database.BatchableContext object.
      • A list of sObjects, such as List, or a list of parameterized types. If you are using a Database.QueryLocator, the returned list should be used.
      • Batches of records are not guaranteed to execute in the order they are received from the start method.

  • The finish method is called after all batches are processed.
    • Use this method to send confirmation emails or execute post-processing operations.


Note:

  • All of the methods in the Database.Batchable interface require a reference to a Database.BatchableContext object. Use this object to track the progress of the batch job.
  • Each execution of a batch Apex job is considered a discrete transaction.
    • For example, a batch Apex job that contains 1,000 records and is executed without the optional scope parameter from Database.executeBatch is considered five transactions of 200 records each.
    • The Apex governor limits are reset for each transaction. If the first transaction succeeds but the second fails, the database updates made in the first transaction are not rolled back.


Some code snippets

global class BatchUpdateOfferCodeOnOppty implements Database.Batchable {

      //Constructor
    global BatchUpdateOfferCodeOnOppty(){
        listCampaign = [select Id, Offer_code__c from Campaign where Has_Offer_Code__c = true];
    }

    global Database.QueryLocator start(Database.BatchableContext BC){
        return Database.getQueryLocator([select Id, Offer_code__c, CampaignId from Opportunity where CampaignId IN: listCampaign]);
    }

    global void execute(Database.BatchableContext BC, List scope){
        ......
        //Prepare map of Campaign Offer Code to update on Opportunity
        ......
        //Use scope to get the list of Opportunity returned from start method
        ......
        //Update the offer code on Opportunity
        ......
        Database.update(listOpportunity);
        ......
        //Get the list of save result to check for failed updates
          .........
        // Update the failed campaign
        ......
    }

    global void finish(Database.BatchableContext ctx){
        /Compose Async Apex Job info
        AsyncApexJob oAsyncApexJob = [ SELECT Id, ApexClassId,
                                       JobItemsProcessed,
                                       TotalJobItems,
                                       NumberOfErrors,
                                       ExtendedStatus,
                                       CreatedBy.Email
                                       FROM AsyncApexJob
                                       WHERE id =: ctx.getJobId()];
        ......
        ......
       //Compose Single EmailMessage service             
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();     
        String[] sToAddress = new String[]{'sudhir.kumarjaiswal@thomsonreuters.com'};
        mail.setToAddresses(sToAddress);
        mail.setReplyTo('noreply@salesforce.com');                      
        mail.setSenderDisplayName('Batch Job Summary');
        mail.setSubject('Batch Job Summary: Update Campaign Offer Code on Opportunity');
        mail.setPlainTextBody(sEmailMessage);
        mail.setHtmlBody(sEmailMessage);
        //send email in case of no errors
        if(oAsyncApexJob.NumberOfErrors > 0 ){
            Messaging.sendEmail( new Messaging.SingleEmailMessage[]{mail});
        }
                     
    }

 Wanted to know how to write Test Class for a Batch Apex Class....?  Coming soon..     Published here

To know more

1 comment:

  1. To be pedantic if two things are mutually exclusive it means that they can *never* happen together not that they are independent events

    ReplyDelete

Thank you for visiting. Your comments are highly appreciated.