Skip to content

Commit a216689

Browse files
authored
Merge pull request #1560 from bmacarini/feature/scheduledRollupErrorEmailsSpecificLookupInfo
Feature: Enhanced Rollup Error Emails (Scheduled & Batch)
2 parents 2d808e3 + 1aa12fc commit a216689

File tree

4 files changed

+129
-12
lines changed

4 files changed

+129
-12
lines changed

dlrs/main/classes/RollupCalculateJob.cls

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,19 +113,41 @@ public with sharing class RollupCalculateJob implements Database.Batchable<sObje
113113
// Retrieve organization info to put in the email
114114
Organization org = [SELECT Id, Name FROM Organization];
115115

116+
//Getting rollup name and unique name
117+
String rollupName = rollup.isEmpty() ? '' : rollup[0].Name;
118+
String rollupUniqueName = rollup.isEmpty() ? '' : rollup[0].UniqueName;
119+
116120
// Errors are emailed to the user that scheduled this job
117121
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
118-
mail.setToAddresses(new List<String>{ UserInfo.getUserId() });
122+
mail.setTargetObjectId(UserInfo.getUserId());
123+
mail.setSaveAsActivity(false); // required when sending to user
119124
mail.setSubject(
120125
String.format(
121-
'Apex job {0} failed to update rollups in {1} ({2})',
122-
new List<String>{ BC.getJobId(), org.Name, org.Id }
126+
'Apex job "{0}" failed to update rollups in "{1} (ID: {2})"',
127+
new List<String>{ rollupName, org.Name, org.Id }
123128
)
124129
);
125130
mail.setPlainTextBody(
126131
String.format(
127-
'Error: {0}. Parent record Ids {1}',
128-
new List<String>{ e.getMessage(), String.join(ids, ',') }
132+
'Rollup Execution Failed\n\n' +
133+
'--------------------------------------------------------------------------------\n' +
134+
'Organization Name: {0}\n' +
135+
'Organization ID: {1}\n' +
136+
'Lookup: {2} (Unique Name: {3}, ID: {4})\n' +
137+
'Apex Job ID: {5}\n\n' +
138+
'Error Message: {6}\n\n' +
139+
'Parent records in scope that caused the failure: {7}\n' +
140+
'--------------------------------------------------------------------------------',
141+
new List<String>{
142+
org.Name,
143+
org.Id,
144+
rollupName,
145+
rollupUniqueName,
146+
lookupId,
147+
BC.getJobId(),
148+
e.getMessage(),
149+
String.join(ids, ',')
150+
}
129151
)
130152
);
131153
MessageService.sendEmail(new List<Messaging.SingleEmailMessage>{ mail });

dlrs/main/classes/RollupCalculateJobSchedulable.cls

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,47 @@ public with sharing class RollupCalculateJobSchedulable implements Schedulable {
4949
String jobRef = jobNameByTriggerId.size() == 0
5050
? 'id ' + triggerId
5151
: 'named ' + jobNameByTriggerId.get(triggerId) + ' (' + triggerId + ')';
52+
53+
// Retrieve organization info to put in the email
54+
Organization org = [SELECT Id, Name FROM Organization];
55+
56+
//Getting rollup name and unique name
57+
String rollupName = rollup.isEmpty() ? '' : rollup[0].Name;
58+
String rollupuniqueName = rollup.isEmpty() ? '' : rollup[0].UniqueName;
59+
5260
// Errors are emailed to the user that scheduled this job
5361
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
54-
mail.setToAddresses(new List<String>{ UserInfo.getUserId() });
62+
mail.setTargetObjectId(UserInfo.getUserId());
63+
mail.setSaveAsActivity(false); // required when sending to user
5564
mail.setSubject(
5665
String.format(
57-
'Apex scheduled job {0} failed to run rolllup',
58-
new List<String>{ jobRef }
66+
'Apex scheduled job "{0}" failed to update rollups in "{1} (ID: {2})"',
67+
new List<String>{ jobRef, org.Name, org.Id }
5968
)
6069
);
6170
mail.setPlainTextBody(
6271
String.format(
63-
'Error: {0} ' +
64-
'Review the error, rollup definition and/or delete the Apex Scheduled job under Setup. ' +
65-
'Check if the rollup still exists via the Manage Rollup Summaries and/or Lookup Rollup Summaries tabs. ',
66-
new List<String>{ e.getMessage() }
72+
'Failed Job Information\n\n' +
73+
'Review the error, rollup definition and/or delete the Apex Scheduled job under Setup.\n' +
74+
'Check if the rollup still exists via the Manage Rollup Summaries and/or Lookup Rollup Summaries tabs.\n\n' +
75+
'--------------------------------------------------------------------------------\n' +
76+
'Organization Name: {0}\n' +
77+
'Organization ID: {1}\n\n' +
78+
'Lookup: {2} (Unique Name: {3}, ID: {4})\n' +
79+
'Apex Scheduled Job Name: {5}\n' +
80+
'Trigger ID: {6} \n\n' +
81+
'Error Message: {7}\n' +
82+
'--------------------------------------------------------------------------------',
83+
new List<String>{
84+
org.Name,
85+
org.Id,
86+
rollupName,
87+
rollupuniqueName,
88+
rollupRecordId,
89+
jobRef,
90+
triggerId,
91+
e.getMessage()
92+
}
6793
)
6894
);
6995
MessageService.sendEmail(new List<Messaging.SingleEmailMessage>{ mail });

dlrs/main/classes/RollupCalculateJobSchedulableTest.cls

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,43 @@ private class RollupCalculateJobSchedulableTest {
8282
Assert.areEqual(rollupSummary.Id, logs[0].ParentId__c);
8383
Assert.areEqual(0, MessageService.sentEmailList.size());
8484
}
85+
86+
// Mock class to simulate SchedulableContext
87+
public class MockSchedulableContext implements SchedulableContext {
88+
public Id getTriggerId() {
89+
// CronTigger fake Id
90+
return '08e000000000000AAA';
91+
}
92+
}
93+
94+
@isTest
95+
public static void testRollupNameNotFoundCase() {
96+
String prefix = LookupRollupSummary2__mdt.sObjectType.getDescribe()
97+
.getKeyPrefix();
98+
99+
String fakeRollupId = prefix + '00000000000000D';
100+
101+
//Selector finds no rollup, so when the schedulable runs it will throw exception
102+
RollupSummariesSelector.setRollupCache(
103+
false,
104+
false,
105+
new List<RollupSummary>()
106+
);
107+
108+
RollupCalculateJobSchedulable job = new RollupCalculateJobSchedulable(
109+
fakeRollupId,
110+
null
111+
);
112+
113+
Test.startTest();
114+
job.execute(new MockSchedulableContext());
115+
Test.stopTest();
116+
117+
List<LookupRollupSummaryLog__c> logs = [
118+
SELECT Id, ParentId__c, ParentObject__c, ErrorMessage__c
119+
FROM LookupRollupSummaryLog__c
120+
];
121+
122+
assert.areEqual(1, logs.size());
123+
}
85124
}

dlrs/main/classes/RollupCalculateJobTest.cls

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,4 +296,34 @@ private class RollupCalculateJobTest {
296296
return '100000000000000';
297297
}
298298
}
299+
300+
@isTest
301+
public static void testRollupNameNotFoundCase() {
302+
String prefix = LookupRollupSummary2__mdt.sObjectType.getDescribe()
303+
.getKeyPrefix();
304+
305+
String fakeRollupId = prefix + '00000000000000D';
306+
307+
RollupSummariesSelector.setRollupCache(
308+
false,
309+
false,
310+
new List<RollupSummary>()
311+
);
312+
313+
Account a = new Account(Name = 'Test');
314+
insert a;
315+
316+
RollupCalculateJob job = new RollupCalculateJob(fakeRollupId);
317+
318+
Test.startTest();
319+
job.execute(new MockBatchableContext(), new List<SObject>{ a });
320+
Test.stopTest();
321+
322+
List<LookupRollupSummaryLog__c> logs = [
323+
SELECT Id, ParentId__c, ParentObject__c, ErrorMessage__c
324+
FROM LookupRollupSummaryLog__c
325+
];
326+
327+
assert.areEqual(0, logs.size());
328+
}
299329
}

0 commit comments

Comments
 (0)