You need to sign in to do that
Don't have an account?
Sangeeta10
Status of each record processed in a batch apex
I created a batch apex and schedulable apex and scheduled apex to send emails to all contacts on an Account associated with an open case of a specific sub-category. The batch apex works but there are some batch failures, I am unable to know status of each record in a batch as to whom email was sent and not and the reason behind batch failure. On an average there are about 833 records processed in 85 batches out of which 52 batches got failed. Not sure how many records in each batch got failed and why. How can I get status of 833 records which ones got processed and which ones got failed? Below is my batch class and schedulable class.
Batch Apex:
global class CaseNotifications implements Database.Batchable<sObject>,Database.Stateful {
global string contactIds;
global integer count = 0;
global Database.QueryLocator start(Database.BatchableContext BC)
{
string subcategory1='Hardware';
string subcategory2='Software';
return Database.getQueryLocator('select id from contact where accountId in (select accountId from case where Isclosed= false and (sub_category__c=\''+subcategory1+'\' or sub_category__c=\''+subcategory2+'\'))' );
}
global void execute(Database.BatchableContext BC, List<sObject> scopeList) {
List<Messaging.SingleEmailMessage> emails = new list<Messaging.SingleEmailMessage>();
List<Contact> toAddresses=new List<Contact> ([select email from contact where id in :scopelist]);
system.debug('ContactIds size'+toaddresses.size());
if(toAddresses.size()>0){
for(Contact c:toAddresses){
if(c.email!=null){
count++;
Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
Message.setTargetObjectId(c.id);
Message.setTemplateId('00Xj00000011tbR');
Message.setOrgWideEmailAddressId('0D2j00000000BAM');
emails.add(Message);
}}
Messaging.sendEmail(emails);
}
}
global void finish(Database.BatchableContext BC){
AsyncApexJob aaj = [Select Id, Status, NumberOfErrors, JobItemsProcessed, MethodName, TotalJobItems, CreatedBy.Email from AsyncApexJob where Id =:BC.getJobId()];
// Send an email to the Apex job's submitter notifying of job completion.
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {aaj.CreatedBy.Email};
mail.setToAddresses(toAddresses);
mail.setSubject('JOB Salesforce Send Notification Batch: ' + aaj.Status);
String bodyText='Batches Processed ' + aaj.TotalJobItems + 'Total number of records processed ' + count+ 'with '+ aaj.NumberOfErrors + ' batch failures.\n';
mail.setPlainTextBody(bodyText);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
Schedulable Apex:
global class BackupCaseNotifications implements schedulable {
global void execute(SchedulableContext ctx) {
CaseNotifications b=new CaseNotifications();
Database.executeBatch(b,10);
}
}
Batch Apex:
global class CaseNotifications implements Database.Batchable<sObject>,Database.Stateful {
global string contactIds;
global integer count = 0;
global Database.QueryLocator start(Database.BatchableContext BC)
{
string subcategory1='Hardware';
string subcategory2='Software';
return Database.getQueryLocator('select id from contact where accountId in (select accountId from case where Isclosed= false and (sub_category__c=\''+subcategory1+'\' or sub_category__c=\''+subcategory2+'\'))' );
}
global void execute(Database.BatchableContext BC, List<sObject> scopeList) {
List<Messaging.SingleEmailMessage> emails = new list<Messaging.SingleEmailMessage>();
List<Contact> toAddresses=new List<Contact> ([select email from contact where id in :scopelist]);
system.debug('ContactIds size'+toaddresses.size());
if(toAddresses.size()>0){
for(Contact c:toAddresses){
if(c.email!=null){
count++;
Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
Message.setTargetObjectId(c.id);
Message.setTemplateId('00Xj00000011tbR');
Message.setOrgWideEmailAddressId('0D2j00000000BAM');
emails.add(Message);
}}
Messaging.sendEmail(emails);
}
}
global void finish(Database.BatchableContext BC){
AsyncApexJob aaj = [Select Id, Status, NumberOfErrors, JobItemsProcessed, MethodName, TotalJobItems, CreatedBy.Email from AsyncApexJob where Id =:BC.getJobId()];
// Send an email to the Apex job's submitter notifying of job completion.
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {aaj.CreatedBy.Email};
mail.setToAddresses(toAddresses);
mail.setSubject('JOB Salesforce Send Notification Batch: ' + aaj.Status);
String bodyText='Batches Processed ' + aaj.TotalJobItems + 'Total number of records processed ' + count+ 'with '+ aaj.NumberOfErrors + ' batch failures.\n';
mail.setPlainTextBody(bodyText);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
Schedulable Apex:
global class BackupCaseNotifications implements schedulable {
global void execute(SchedulableContext ctx) {
CaseNotifications b=new CaseNotifications();
Database.executeBatch(b,10);
}
}
Hi Sangeeta,
You can create a custom object to log errors.Create a object with name "Logs" & add some fields like Classname(Error origination clas),method name(Error origination method),StackTrace(Stacktrace of error),Error message(Error/exceptipon message),Batch Id(Id of failed batch)
Create a instance varaible of this type List<Log object> in the batch. Use this instnace to store your logs while batch is running(execute method) and insert them all at once in the finish() method. You will have to implement Database.Stateful interface ,which you have already done,to ensure that your instance variable is retains state across transactions.
Hope this helps.
Regards,
Karan
Kindly use Messaging.SendEmailResult[] like below pseudo code.
Knowledge link: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_email_outbound_messaging.htm
Thanks
lokesh
global class CaseNotifications implements Database.Batchable<sObject>,Database.Stateful {
global string contactIds;
global integer count = 0;
global Database.QueryLocator start(Database.BatchableContext BC)
{
string subcategory1='Hardware';
string subcategory2='Software';
return Database.getQueryLocator('select id from contact where accountId in (select accountId from case where Isclosed= false and (sub_category__c=\''+subcategory1+'\' or sub_category__c=\''+subcategory2+'\'))' );
}
global void execute(Database.BatchableContext BC, List<sObject> scopeList) {
List<Messaging.SingleEmailMessage> emails = new list<Messaging.SingleEmailMessage>();
List<Contact> toAddresses=new List<Contact> ([select email from contact where id in :scopelist]);
system.debug('ContactIds size'+toaddresses.size());
if(toAddresses.size()>0){
for(Contact c:toAddresses){
if(c.email!=null){
count++;
Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
Message.setTargetObjectId(c.id);
Message.setTemplateId('00Xj00000011tbR');
Message.setOrgWideEmailAddressId('0D2j00000000BAM');
emails.add(Message);
}}
Messaging.SendEmailResult[] results = Messaging.sendEmail(emails,false);
inspectResults(results);
}
}
global void finish(Database.BatchableContext BC){
AsyncApexJob aaj = [Select Id, Status, NumberOfErrors, JobItemsProcessed, MethodName, TotalJobItems, CreatedBy.Email from AsyncApexJob where Id =:BC.getJobId()];
// Send an email to the Apex job's submitter notifying of job completion.
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {aaj.CreatedBy.Email};
mail.setToAddresses(toAddresses);
mail.setSubject('JOB Salesforce Send Notification Batch: ' + aaj.Status);
String bodyText='Batches Processed ' + aaj.TotalJobItems + 'Total number of records processed ' + count+ 'with '+ aaj.NumberOfErrors + ' batch failures.\n';
mail.setPlainTextBody(bodyText);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
private static Boolean inspectResults(Messaging.SendEmailResult[] results) {
Boolean sendResult = true;
// sendEmail returns an array of result objects.
// Iterate through the list to inspect results.
// In this class, the methods send only one email,
// so we should have only one result.
for (Messaging.SendEmailResult res : results) {
if (res.isSuccess()) {
System.debug('Email sent successfully');
}
else {
sendResult = false;
System.debug('The following errors occurred: ' + res.getErrors());
//email error
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setSaveAsActivity(false);
mail.setTargetObjectId('005j000000GFiun');
mail.setSubject('error for email in the batch'+ res.getErrors());
mail.setBccSender(false);
mail.setUseSignature(false);
mail.setPlainTextBody('error for email in the batch' + res.getErrors());
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
return sendResult;
}
}