Recipes by Category

App Distribution (2) Bundle logic, interface and services for distribution. App Logic (37) The Apex programming language, workflow and formulas for logic. Collaboration (6) The Salesforce Chatter collaboration platform. Database (29) Data persistence, reporting and analytics. Integration (33) Web Service APIs and toolkits for integration. Security (9) Platform, application and data security. Tools (4) Force.com tooling User Interface (36) Visualforce MVC and metadata-drive user interfaces. Web Sites (12) Public web sites and apps with optional user registration and login.
Beta Feedback
Cookbook Home » Serialize Batch Apex

Serialize Batch Apex

Post by DevendraNatani  (2011-06-20)

Status: Unverified
Level: novice

Problem

You want to execute more than one set of batch Apex processing, but the default Force.com setup doesn't allow you to call one batch Apex class from another.

Description

In Force.com you cannot call a batch Apex class from another batch Apex class because batch Apex is a future call. However, you can use Force.com email services to serialize these batch processes.

To put this into action, you need to create an email service to send an email after a batch is complete, modify the first batch class to call this service after completion, and create an inbound email handler to intercept the email and start the second batch.

Create a class "EmailHandler" . The purpose of this class is to send email to the Force.com email service address.

public class EmailHandler
{
    public static void sendEmail(string body)
    {
       Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
       // email address of the salesforce email service
       String[] toAddresses = new String[] {'myhandler@x4m9vxsizy32oug74yh6rhj7e.in.salesforce.com'};
       mail.setToAddresses(toAddresses);
       mail.setSubject('Test Batch' );
       mail.setPlainTextBody(body);
       Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
    }
    
}

You'll want to use the email address of the email service configured later in this recipe, in the toAddresses array.

Now create two Batch Apex classes. These are the sample batch classes:

 global class Batch1 implements Database.Batchable<Sobject>{
        //constructor
        global Batch1(){}
            
        
        //Method to get the data to be proceesed  
        global database.Querylocator start(Database.BatchableContext context){
            string query = 'select id, name from Account limit 1000';
            return Database.getQueryLocator(query);
        }
            
         
        //Method to execute the batch
        global void execute(Database.BatchableContext context , Sobject[] scope){
            for(Sobject s : scope){ 
                Account a = (Account)s;
                // TO DO
                // add your logic 
            }
        }
         
         //Method to be called after the excute
         global void finish(Database.BatchableContext context){
             // send an email
             EmailHandler.sendEmail('start second batch');
         }
}
global class Batch2 implements Database.Batchable<Sobject>{
        //constructor
        global Batch2(){}
            
        
        //Method to get the data to be proceesed  
        global database.Querylocator start(Database.BatchableContext context){
            string query = 'select id, name from Contact limit 1000';
            return Database.getQueryLocator(query);
        }
            
         
        //Method to execute the batch
        global void execute(Database.BatchableContext context , Sobject[] scope){
            for(Sobject s : scope){ 
                Contact c = (Contact)s;
                // TO DO
                // add your logic 
            }
        }
         
         //Method to be called after the excute
         global void finish(Database.BatchableContext context){
         
         }
}

Notice how the finish() method in Batch1 calls the email service.

Finally, create a class which implements Messaging.InboundEmailHandler.

global class EmailServiceHandler implements Messaging.InboundEmailHandler 
{
        global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email,Messaging.InboundEnvelope envelope) 
        {
    if (email.plainTextBody== 'start second batch')
           {
              // create the instance of second batch class
              Batch2 obj = new Batch2();
              Database.executeBatch(obj);
           } 
           Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();
    return result;
 }
}

Make sure that the email address assigned to this service is used in the EmailHandler class.

Now execute the Batch1 class. After execution, it will call the email service, which will result in an email being sent and intercepted by the EmailServiceHandler, which will execute the second batch.

 Batch1 obj = new Batch1();
 Database.executeBatch(obj);

References

Share

Recipe Activity - Please Log in to write a comment

This is a great solution to this previous limitation with batch jobs.  Starting a batch APEX job from another batch APEX job is now possible directly.  In the Finalize event the Database.scheduleBatch method can be called.

by Terry Luschen  (2013-08-05)

Thank you

voted as verified by Shivanath Devinarayanan  (2013-04-24)

Figured out the problem. The To Address on the custom settings object was set to the Email type, which could not handle the length of the sandbox service address. Things worked seamlessly after changing the To Address to Text(255).

by Daniel Ho  (2012-11-09)

I'm using the E2A code from Github and works beautifully. The only issue I have is that on the sandbox when the APEX code sends the email directly to the email service nothing seems to be happening. However if I forward the same email to the service then the sevice handler executes and the batch is scheduled properly. Suggestions?

by Daniel Ho  (2012-11-09)

awesome reciepe

by Mohith Shrivastava  (2012-07-21)

Awesome Reciepe .

by Mohith Shrivastava  (2012-07-21)

Hi Devendra,

Thanks a lot... Its working fine..

And i have a doubt.. If i am having a class, Through that class i am passing the list values in to second batch apex for execution. if i used this serialization process. How can i pass the values to second batch... Please help me..

Thanks

by Boggarapu Nagalakshmi  (2012-07-09)

Inspired by your code I've created a small Toolkit 'Email2Apex' to make it more generic solution and to support parameters. check out: https://github.com/sbwdev/Email2Apex

by Sebastian Wagner  (2012-02-06)

Just kidding - can't insert EmailServicesFunction from apex :(

by a093000000NWsBE  (2012-01-22)

Hmm-on second thought, I can have some "activate" button create the EmailServicesFunction & EmailServicesAddress on install, which eliminates the manual error issue.  

by a093000000NWsBE  (2012-01-22)

Love the idea!  I wanted to use this for a managed package, but it appears Email Settings can't be packaged, so it would be pretty painful for the installer to set up the setting as if they get anything wrong, the code would break.

by a093000000NWsBE  (2012-01-22)

I found the problem - The sandbox includes the text "Force.com sandbox" in both the subject and body of outbound emails.  Also, when I try to use the contains() strting method on email.plainTextBody, it doesn't work, so I have to use the Subject field instead.

by dmcheng602092010  (2011-12-29)

Hello.  Thanks for posting this.  I'm trying to implement in a sandbox but the EmailServiceHandler is not doing anything when the first batch sends the email.  I have set the Inbound Email Service to accept mail from all domains, and the EmailServiceHandler works fine when I send an email from gmail.com, yahoo.com, etc.  I've double-checked the To address in the EmailHandler class.

Any suggestions?

Thanks
David

by dmcheng602092010  (2011-12-29)

Nice recipe Deva ....

by Ranjeet.Singh.Chouhan  (2011-12-17)

This definitely works...

by Sandeep Mahal  (2011-12-15)
Page 1 of  2

X

Vote to Verify a Recipe

Verifying a recipe is a way to give feedback to others and broaden your own understanding of the capabilities on Force.com. When you verify a recipe, please make sure the code runs, and the functionality solves the articulated problem as expected.

Please make sure:
  • All the necessary pieces are mentioned
  • You have tested the recipe in practice
  • Have sent any suggestions for improvements to the author

Please Log in to verify a recipe

You have voted to verify this recipe.