Interest Manager Batch Jobs
Last Updated: Oct 2, 2026
Operational guide for the scheduled/batch Apex jobs shipped with Interest Manager.
| Class | Type | Purpose | Default schedule | Batch size |
|---|---|---|---|---|
FPMRuleRecalcBatch |
Batchable + Schedulable | Re-evaluates research eligibility on Preference Rules | Daily 01:00 | 200 |
FPMPreferenceSearchStorageBatchDelete |
Batchable (Stateful) | Purges old Search Result rows from FPM_Log__c |
Run through the cleaner below | 2000 |
FPMPreferenceSearchStorageCleaner |
Schedulable (wrapper) | Schedules/launches the purge batch with a retention period and an optional key filter | Daily 02:00 (all results, 7 days), daily 03:00 (UI cache, 1 day) | 2000 |
1. FPMRuleRecalcBatch – Research Eligibility Recalculation
Purpose
Makes sure a Preference Rule's research access matches the Contact's current eligibility. A rule's eligibility can change with no edit to the rule itself, for example when:
- A Contact or Account attribute used by a research validation rule changes (e.g. Account Tier).
- The rule's configuration changes indirectly (e.g. delivery options removed or added outside the Rule Builder).
- A temporary research approval starts or ends its effective date range (
Start_Date__c/End_Date__c).
What it processes
Preference_Rule__c records where:
Is_Active__c = trueResearch_Status__c != 'Pending for Approval'Contact__c != null
Each rule is checked with FPMResearchRuleValidationService.validatePreferenceRuleEligibility(...).
Outcome per record
| Current state | Evaluation | Action |
|---|---|---|
Not Inactive |
Not eligible | Set Research_Status__c = Inactive, set Research_Inactive_Rule__c to the first failing rule |
Inactive |
Eligible | Clear research status (FPMRuleController.clearResearchStatus) |
Not Inactive |
Delivery_Options__c blank |
Set to Inactive (no failing rule name) |
| Anything else | – | No change (record is not updated) |
Only changed records are updated. Each chunk gets its own FPMTransactionContext.batchId, so the audit log can group the changes made by one run.
How to run
Schedule (recommended) – Developer Console › Execute Anonymous:
String cron = '0 0 1 * * ?'; // 01:00 daily
System.schedule('FPM Rule Research Recalc - Daily', cron, new FPMRuleRecalcBatch());
Run once on demand (e.g. after a bulk Account/Contact data load or a change to research validation rules):
Database.executeBatch(new FPMRuleRecalcBatch(), 200);
Running it on demand is the only way to use a batch size other than 200; the scheduled entry point always uses 200.
Recommendations
- Frequency: Daily. It is safe to run more often (e.g. every 4–6 hours) if temporary approvals need to take effect within the same day. Running it less than daily means research access can stay wrong for more than a day after the effective date passes.
- Time window: Off-hours, before the business day starts and after the nightly data loads/integrations that update Contact/Account attributes.
- Running user: The job evaluates eligibility as the user who scheduled it (
UserInfo.getUserId()), and records that user as the acting user in the audit log. Schedule it as a dedicated admin/integration user who can see all Contacts, Accounts and Preference Rules. A user with limited visibility can produce wrong eligibility results. - Expected duration: Runtime grows with the number of active Preference Rules (one validation call per rule). As a rule of thumb, plan for minutes for tens of thousands of rules. Check the actual runtime in your org (Setup › Apex Jobs) after the first run and keep it well inside the off-hours window.
- Batch size: Keep the default of 200. If you see CPU time or SOQL limit errors (orgs with many research validation rules), run on demand with 50–100.
- Monitoring: Errors are only written to the debug log. When a DML failure happens, the whole chunk of up to 200 records is not updated and the job still reports success. Check Setup › Apex Jobs for failures, and if research status looks stale, run the job on demand with debug logging turned on for the running user.
2. FPMPreferenceSearchStorageBatchDelete / FPMPreferenceSearchStorageCleaner – Search Result Storage Cleanup
Purpose
Interest Manager search stores result snapshots in FPM_Log__c with Log_Type__c = 'Search Result'. They come from two sources:
| Source | Job_Key__c value |
Growth rate |
|---|---|---|
| Asynchronous / API search jobs | 18‑character Apex Job Id (never contains :) |
Low |
| Synchronous UI list pagination cache (ACE List / Interest Manager Search) | Composite key <aceListId>:<userId>:<criteriaHash>:<nonce> (always contains :) |
High – one per search/paging session |
If they are never removed, these rows use up data storage. The cleanup batch hard-deletes Search Result rows older than a retention period. It can also be limited to one family of keys with a SOQL LIKE pattern, so the fast-growing UI cache can be purged on a shorter schedule without affecting API results.
FPMPreferenceSearchStorageCleaner is the Schedulable wrapper: it passes the retention period and pattern through and runs the batch with a scope of 2000.
Retention behaviour
- Cutoff = midnight (00:00) of
today − retentionDays. Rows are deleted based onCreatedDate, so the time a row is actually kept is betweenretentionDaysandretentionDays + 1days. - The minimum
retentionDaysis 1. Values below 1 are treated as 1. - Pattern
null= allSearch Resultrows (API and UI cache). - Pattern
FPMPreferenceSearchStorageCleaner.UI_CACHE_JOB_ID_PATTERN('%:%') = UI cache rows only. - Partial success is allowed. A row that cannot be deleted is skipped and does not stop the rest of the chunk. Errors are not logged.
- Cleanup does not decide whether a cached snapshot is still served. The UI cache stops using a snapshot after
SyncSearchCacheStalenessMinutes(AFR feature attribute, default 30 minutes), whatever its physical retention. Any UI cache row older than that is just using storage.
How to run
Recommended setup – two schedules (Execute Anonymous):
// 1) All search results (API + UI) – keep 7 days, daily 02:00
System.schedule('FPMPreferenceSearchStorageCleaner_Daily',
'0 0 2 * * ?', new FPMPreferenceSearchStorageCleaner(7));
// 2) UI paging cache only – keep 1 day, daily 03:00
System.schedule('FPMPreferenceSearchStorageCleaner_UICache',
'0 0 3 * * ?',
new FPMPreferenceSearchStorageCleaner(1, FPMPreferenceSearchStorageCleaner.UI_CACHE_JOB_ID_PATTERN));
Helper method (the job name is generated as FPM Preference Search Storage Cleaner plus (<pattern>) when a pattern is given):
FPMPreferenceSearchStorageCleaner.schedule('0 0 2 * * ?', 7);
FPMPreferenceSearchStorageCleaner.schedule('0 0 3 * * ?', 1, FPMPreferenceSearchStorageCleaner.UI_CACHE_JOB_ID_PATTERN);
Job names must be unique. Calling the helper again with the same pattern fails until the existing scheduled job is deleted (Setup › Scheduled Jobs).
Run once on demand (e.g. to free storage right away):
Database.executeBatch(new FPMPreferenceSearchStorageBatchDelete(7), 2000);
// UI cache only
Database.executeBatch(new FPMPreferenceSearchStorageBatchDelete(1, '%:%'), 2000);
Recommendations
| Sweep | Retention | Frequency | Notes |
|---|---|---|---|
| All search results | 7 days (increase if API consumers need to fetch results later) | Daily | API callers must retrieve async job results within this window |
| UI cache only | 1 day (the minimum) | Daily; can be scheduled several times a day in high-volume orgs | Snapshots are stale after 30 min anyway, so shorter retention has no functional impact |
- Time window: Off-hours, after
FPMRuleRecalcBatchhas finished, so the jobs don't compete for async capacity. Stagger the two cleaner schedules (e.g. 02:00 and 03:00). - Expected duration: Usually short (a delete with scope 2000). The first run in an org that has built up a large backlog can take much longer. Consider running it on demand outside business hours before you enable the schedule.
- Storage: Deleted rows go to the Recycle Bin first and are permanently removed by Salesforce later. Expect the storage numbers in Setup › Storage Usage to drop with some delay.
- Running user: Must have delete access to
FPM_Log__c. Use the same admin/integration user as the recalc job.
3. Suggested nightly schedule
| Time | Job | Scheduled job name |
|---|---|---|
| 01:00 | FPMRuleRecalcBatch |
FPM Rule Research Recalc - Daily |
| 02:00 | FPMPreferenceSearchStorageCleaner(7) |
FPMPreferenceSearchStorageCleaner_Daily |
| 03:00 | FPMPreferenceSearchStorageCleaner(1, '%:%') |
FPMPreferenceSearchStorageCleaner_UICache |
Times are in the timezone of the user who schedules the job. Change them to suit your nightly integration window.
4. Operations checklist
- Check status: Setup › Apex Jobs (each run) and Setup › Scheduled Jobs (schedules).
- Stop or reschedule: Delete the schedule in Setup › Scheduled Jobs, or run
System.abortJob(<CronTrigger Id>), then schedule it again. - Deployments: Scheduled Apex locks the class. Delete the schedules before deploying changes to these classes, and schedule them again afterwards (or allow deployments with Apex jobs in Setup › Deployment Settings).
- Sandbox refresh: Scheduled jobs are not copied to a refreshed sandbox. Schedule them again after each refresh.