scc-universal 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +44 -0
- package/.cursor/agents/deep-researcher.md +142 -0
- package/.cursor/agents/doc-updater.md +219 -0
- package/.cursor/agents/eval-runner.md +335 -0
- package/.cursor/agents/learning-engine.md +210 -0
- package/.cursor/agents/loop-operator.md +245 -0
- package/.cursor/agents/refactor-cleaner.md +119 -0
- package/.cursor/agents/sf-admin-agent.md +127 -0
- package/.cursor/agents/sf-agentforce-agent.md +126 -0
- package/.cursor/agents/sf-apex-agent.md +117 -0
- package/.cursor/agents/sf-architect.md +426 -0
- package/.cursor/agents/sf-aura-reviewer.md +369 -0
- package/.cursor/agents/sf-bugfix-agent.md +101 -0
- package/.cursor/agents/sf-flow-agent.md +155 -0
- package/.cursor/agents/sf-integration-agent.md +141 -0
- package/.cursor/agents/sf-lwc-agent.md +123 -0
- package/.cursor/agents/sf-review-agent.md +357 -0
- package/.cursor/agents/sf-visualforce-reviewer.md +465 -0
- package/.cursor/hooks/adapter.js +81 -0
- package/.cursor/hooks/after-file-edit.js +26 -0
- package/.cursor/hooks/after-mcp-execution.js +12 -0
- package/.cursor/hooks/after-shell-execution.js +30 -0
- package/.cursor/hooks/after-tab-file-edit.js +12 -0
- package/.cursor/hooks/before-mcp-execution.js +11 -0
- package/.cursor/hooks/before-read-file.js +13 -0
- package/.cursor/hooks/before-shell-execution.js +29 -0
- package/.cursor/hooks/before-submit-prompt.js +23 -0
- package/.cursor/hooks/pre-compact.js +7 -0
- package/.cursor/hooks/session-end.js +10 -0
- package/.cursor/hooks/session-start.js +10 -0
- package/.cursor/hooks/stop.js +18 -0
- package/.cursor/hooks/subagent-start.js +10 -0
- package/.cursor/hooks/subagent-stop.js +10 -0
- package/.cursor/hooks.json +107 -0
- package/.cursor/skills/aside/SKILL.md +115 -0
- package/.cursor/skills/checkpoint/SKILL.md +50 -0
- package/.cursor/skills/configure-scc/SKILL.md +160 -0
- package/.cursor/skills/continuous-agent-loop/SKILL.md +260 -0
- package/.cursor/skills/mcp-server-patterns/SKILL.md +142 -0
- package/.cursor/skills/model-route/SKILL.md +81 -0
- package/.cursor/skills/prompt-optimizer/SKILL.md +366 -0
- package/.cursor/skills/refactor-clean/SKILL.md +133 -0
- package/.cursor/skills/resume-session/SKILL.md +111 -0
- package/.cursor/skills/save-session/SKILL.md +183 -0
- package/.cursor/skills/search-first/SKILL.md +140 -0
- package/.cursor/skills/security-scan/SKILL.md +142 -0
- package/.cursor/skills/sessions/SKILL.md +124 -0
- package/.cursor/skills/sf-agentforce-development/SKILL.md +449 -0
- package/.cursor/skills/sf-apex-async-patterns/SKILL.md +324 -0
- package/.cursor/skills/sf-apex-best-practices/SKILL.md +421 -0
- package/.cursor/skills/sf-apex-constraints/SKILL.md +79 -0
- package/.cursor/skills/sf-apex-cursor/SKILL.md +336 -0
- package/.cursor/skills/sf-apex-enterprise-patterns/SKILL.md +344 -0
- package/.cursor/skills/sf-apex-testing/SKILL.md +407 -0
- package/.cursor/skills/sf-api-design/SKILL.md +237 -0
- package/.cursor/skills/sf-approval-processes/SKILL.md +312 -0
- package/.cursor/skills/sf-aura-development/SKILL.md +260 -0
- package/.cursor/skills/sf-build-fix/SKILL.md +120 -0
- package/.cursor/skills/sf-data-modeling/SKILL.md +274 -0
- package/.cursor/skills/sf-debugging/SKILL.md +362 -0
- package/.cursor/skills/sf-deployment/SKILL.md +291 -0
- package/.cursor/skills/sf-deployment-constraints/SKILL.md +153 -0
- package/.cursor/skills/sf-devops-ci-cd/SKILL.md +322 -0
- package/.cursor/skills/sf-docs-lookup/SKILL.md +100 -0
- package/.cursor/skills/sf-e2e-testing/SKILL.md +321 -0
- package/.cursor/skills/sf-experience-cloud/SKILL.md +248 -0
- package/.cursor/skills/sf-flow-development/SKILL.md +376 -0
- package/.cursor/skills/sf-governor-limits/SKILL.md +319 -0
- package/.cursor/skills/sf-harness-audit/SKILL.md +139 -0
- package/.cursor/skills/sf-help/SKILL.md +156 -0
- package/.cursor/skills/sf-integration/SKILL.md +479 -0
- package/.cursor/skills/sf-lwc-constraints/SKILL.md +128 -0
- package/.cursor/skills/sf-lwc-development/SKILL.md +302 -0
- package/.cursor/skills/sf-lwc-testing/SKILL.md +387 -0
- package/.cursor/skills/sf-metadata-management/SKILL.md +285 -0
- package/.cursor/skills/sf-platform-events-cdc/SKILL.md +372 -0
- package/.cursor/skills/sf-quickstart/SKILL.md +170 -0
- package/.cursor/skills/sf-security/SKILL.md +330 -0
- package/.cursor/skills/sf-security-constraints/SKILL.md +125 -0
- package/.cursor/skills/sf-soql-constraints/SKILL.md +129 -0
- package/.cursor/skills/sf-soql-optimization/SKILL.md +353 -0
- package/.cursor/skills/sf-tdd-workflow/SKILL.md +332 -0
- package/.cursor/skills/sf-testing-constraints/SKILL.md +198 -0
- package/.cursor/skills/sf-trigger-constraints/SKILL.md +88 -0
- package/.cursor/skills/sf-trigger-frameworks/SKILL.md +343 -0
- package/.cursor/skills/sf-visualforce-development/SKILL.md +259 -0
- package/.cursor/skills/strategic-compact/SKILL.md +205 -0
- package/.cursor/skills/update-docs/SKILL.md +162 -0
- package/.cursor/skills/update-platform-docs/SKILL.md +86 -0
- package/.cursor-plugin/plugin.json +26 -0
- package/LICENSE +21 -0
- package/README.md +522 -0
- package/agents/deep-researcher.md +145 -0
- package/agents/doc-updater.md +222 -0
- package/agents/eval-runner.md +340 -0
- package/agents/learning-engine.md +211 -0
- package/agents/loop-operator.md +247 -0
- package/agents/refactor-cleaner.md +122 -0
- package/agents/sf-admin-agent.md +131 -0
- package/agents/sf-agentforce-agent.md +132 -0
- package/agents/sf-apex-agent.md +124 -0
- package/agents/sf-architect.md +435 -0
- package/agents/sf-aura-reviewer.md +372 -0
- package/agents/sf-bugfix-agent.md +105 -0
- package/agents/sf-flow-agent.md +159 -0
- package/agents/sf-integration-agent.md +146 -0
- package/agents/sf-lwc-agent.md +127 -0
- package/agents/sf-review-agent.md +366 -0
- package/agents/sf-visualforce-reviewer.md +468 -0
- package/assets/logo.svg +18 -0
- package/docs/ARCHITECTURE.md +133 -0
- package/docs/authoring-guide.md +373 -0
- package/docs/hook-development.md +578 -0
- package/docs/token-optimization.md +139 -0
- package/docs/workflow-examples.md +645 -0
- package/examples/agentforce-action/README.md +227 -0
- package/examples/apex-trigger-handler/README.md +114 -0
- package/examples/devops-pipeline/README.md +325 -0
- package/examples/flow-automation/README.md +188 -0
- package/examples/integration-pattern/README.md +416 -0
- package/examples/lwc-component/README.md +180 -0
- package/examples/platform-events/README.md +492 -0
- package/examples/scratch-org-setup/README.md +138 -0
- package/examples/security-audit/README.md +244 -0
- package/examples/visualforce-migration/README.md +314 -0
- package/hooks/hooks.json +338 -0
- package/hooks/memory-persistence/README.md +73 -0
- package/manifests/install-modules.json +217 -0
- package/manifests/install-profiles.json +17 -0
- package/mcp-configs/mcp-servers.json +19 -0
- package/package.json +89 -0
- package/schemas/hooks.schema.json +123 -0
- package/schemas/install-modules.schema.json +76 -0
- package/schemas/install-profiles.schema.json +28 -0
- package/schemas/install-state.schema.json +73 -0
- package/schemas/package-manager.schema.json +18 -0
- package/schemas/plugin.schema.json +112 -0
- package/schemas/scc-install-config.schema.json +29 -0
- package/schemas/state-store.schema.json +111 -0
- package/scripts/cli/install-apply.js +170 -0
- package/scripts/cli/uninstall.js +193 -0
- package/scripts/hooks/check-console-log.js +101 -0
- package/scripts/hooks/check-hook-enabled.js +17 -0
- package/scripts/hooks/check-platform-docs-age.js +48 -0
- package/scripts/hooks/cost-tracker.js +78 -0
- package/scripts/hooks/doc-file-warning.js +63 -0
- package/scripts/hooks/evaluate-session.js +98 -0
- package/scripts/hooks/governor-check.js +220 -0
- package/scripts/hooks/learning-observe.sh +206 -0
- package/scripts/hooks/mcp-health-check.js +588 -0
- package/scripts/hooks/post-bash-build-complete.js +34 -0
- package/scripts/hooks/post-bash-pr-created.js +43 -0
- package/scripts/hooks/post-edit-console-warn.js +61 -0
- package/scripts/hooks/post-edit-format.js +79 -0
- package/scripts/hooks/post-edit-typecheck.js +98 -0
- package/scripts/hooks/post-write.js +168 -0
- package/scripts/hooks/pre-bash-git-push-reminder.js +35 -0
- package/scripts/hooks/pre-bash-tmux-reminder.js +47 -0
- package/scripts/hooks/pre-compact.js +51 -0
- package/scripts/hooks/pre-tool-use.js +163 -0
- package/scripts/hooks/pre-write-doc-warn.js +9 -0
- package/scripts/hooks/quality-gate.js +251 -0
- package/scripts/hooks/run-with-flags-shell.sh +32 -0
- package/scripts/hooks/run-with-flags.js +135 -0
- package/scripts/hooks/session-end-marker.js +29 -0
- package/scripts/hooks/session-end.js +311 -0
- package/scripts/hooks/session-start.js +202 -0
- package/scripts/hooks/sfdx-scanner-check.js +142 -0
- package/scripts/hooks/sfdx-validate.js +119 -0
- package/scripts/hooks/stop-hook.js +170 -0
- package/scripts/hooks/suggest-compact.js +67 -0
- package/scripts/lib/agent-adapter.js +82 -0
- package/scripts/lib/apex-analysis.js +194 -0
- package/scripts/lib/hook-flags.js +74 -0
- package/scripts/lib/install-config.js +73 -0
- package/scripts/lib/install-executor.js +363 -0
- package/scripts/lib/install-state.js +121 -0
- package/scripts/lib/orchestration-session.js +299 -0
- package/scripts/lib/package-manager.js +124 -0
- package/scripts/lib/project-detect.js +228 -0
- package/scripts/lib/schema-validator.js +190 -0
- package/scripts/lib/skill-adapter.js +100 -0
- package/scripts/lib/state-store.js +376 -0
- package/scripts/lib/tmux-worktree-orchestrator.js +598 -0
- package/scripts/lib/utils.js +313 -0
- package/scripts/scc.js +164 -0
- package/skills/_reference/AGENTFORCE_PATTERNS.md +112 -0
- package/skills/_reference/APEX_CURSOR.md +159 -0
- package/skills/_reference/API_VERSIONS.md +78 -0
- package/skills/_reference/APPROVAL_PROCESSES.md +105 -0
- package/skills/_reference/ASYNC_PATTERNS.md +163 -0
- package/skills/_reference/AURA_COMPONENTS.md +146 -0
- package/skills/_reference/DATA_MIGRATION_PATTERNS.md +151 -0
- package/skills/_reference/DATA_MODELING.md +124 -0
- package/skills/_reference/DEBUGGING_TOOLS.md +140 -0
- package/skills/_reference/DEPLOYMENT_CHECKLIST.md +87 -0
- package/skills/_reference/DEPRECATIONS.md +79 -0
- package/skills/_reference/DOCKER_CI_PATTERNS.md +138 -0
- package/skills/_reference/ENTERPRISE_PATTERNS.md +122 -0
- package/skills/_reference/EXPERIENCE_CLOUD.md +143 -0
- package/skills/_reference/FLOW_PATTERNS.md +113 -0
- package/skills/_reference/GOVERNOR_LIMITS.md +77 -0
- package/skills/_reference/INTEGRATION_PATTERNS.md +105 -0
- package/skills/_reference/LWC_PATTERNS.md +79 -0
- package/skills/_reference/METADATA_TYPES.md +115 -0
- package/skills/_reference/NAMING_CONVENTIONS.md +84 -0
- package/skills/_reference/PACKAGE_DEVELOPMENT.md +150 -0
- package/skills/_reference/PLATFORM_EVENTS.md +121 -0
- package/skills/_reference/REPORTING_API.md +143 -0
- package/skills/_reference/SCRATCH_ORG_PATTERNS.md +126 -0
- package/skills/_reference/SECURITY_PATTERNS.md +127 -0
- package/skills/_reference/SHARING_MODEL.md +120 -0
- package/skills/_reference/SOQL_PATTERNS.md +119 -0
- package/skills/_reference/TESTING_STANDARDS.md +96 -0
- package/skills/_reference/TRIGGER_PATTERNS.md +114 -0
- package/skills/_reference/VISUALFORCE_PATTERNS.md +121 -0
- package/skills/aside/SKILL.md +118 -0
- package/skills/checkpoint/SKILL.md +53 -0
- package/skills/configure-scc/SKILL.md +163 -0
- package/skills/continuous-agent-loop/SKILL.md +264 -0
- package/skills/mcp-server-patterns/SKILL.md +146 -0
- package/skills/model-route/SKILL.md +84 -0
- package/skills/prompt-optimizer/SKILL.md +369 -0
- package/skills/refactor-clean/SKILL.md +136 -0
- package/skills/resume-session/SKILL.md +114 -0
- package/skills/save-session/SKILL.md +186 -0
- package/skills/search-first/SKILL.md +144 -0
- package/skills/security-scan/SKILL.md +146 -0
- package/skills/sessions/SKILL.md +127 -0
- package/skills/sf-agentforce-development/SKILL.md +450 -0
- package/skills/sf-apex-async-patterns/SKILL.md +326 -0
- package/skills/sf-apex-best-practices/SKILL.md +425 -0
- package/skills/sf-apex-constraints/SKILL.md +81 -0
- package/skills/sf-apex-cursor/SKILL.md +338 -0
- package/skills/sf-apex-enterprise-patterns/SKILL.md +348 -0
- package/skills/sf-apex-testing/SKILL.md +409 -0
- package/skills/sf-api-design/SKILL.md +238 -0
- package/skills/sf-approval-processes/SKILL.md +315 -0
- package/skills/sf-aura-development/SKILL.md +263 -0
- package/skills/sf-build-fix/SKILL.md +121 -0
- package/skills/sf-data-modeling/SKILL.md +278 -0
- package/skills/sf-debugging/SKILL.md +363 -0
- package/skills/sf-deployment/SKILL.md +295 -0
- package/skills/sf-deployment-constraints/SKILL.md +155 -0
- package/skills/sf-devops-ci-cd/SKILL.md +325 -0
- package/skills/sf-docs-lookup/SKILL.md +103 -0
- package/skills/sf-e2e-testing/SKILL.md +324 -0
- package/skills/sf-experience-cloud/SKILL.md +249 -0
- package/skills/sf-flow-development/SKILL.md +377 -0
- package/skills/sf-governor-limits/SKILL.md +323 -0
- package/skills/sf-harness-audit/SKILL.md +142 -0
- package/skills/sf-help/SKILL.md +159 -0
- package/skills/sf-integration/SKILL.md +483 -0
- package/skills/sf-lwc-constraints/SKILL.md +130 -0
- package/skills/sf-lwc-development/SKILL.md +303 -0
- package/skills/sf-lwc-testing/SKILL.md +388 -0
- package/skills/sf-metadata-management/SKILL.md +288 -0
- package/skills/sf-platform-events-cdc/SKILL.md +375 -0
- package/skills/sf-quickstart/SKILL.md +173 -0
- package/skills/sf-security/SKILL.md +334 -0
- package/skills/sf-security-constraints/SKILL.md +127 -0
- package/skills/sf-soql-constraints/SKILL.md +131 -0
- package/skills/sf-soql-optimization/SKILL.md +354 -0
- package/skills/sf-tdd-workflow/SKILL.md +336 -0
- package/skills/sf-testing-constraints/SKILL.md +200 -0
- package/skills/sf-trigger-constraints/SKILL.md +90 -0
- package/skills/sf-trigger-frameworks/SKILL.md +347 -0
- package/skills/sf-visualforce-development/SKILL.md +260 -0
- package/skills/strategic-compact/SKILL.md +208 -0
- package/skills/update-docs/SKILL.md +165 -0
- package/skills/update-platform-docs/SKILL.md +90 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-apex-async-patterns
|
|
3
|
+
description: "Async Apex patterns — @future, Queueable, Batch, Schedulable, Platform Events, chaining. Use when choosing or implementing async processing. Do NOT use for synchronous Apex or constraint enforcement."
|
|
4
|
+
origin: SCC
|
|
5
|
+
user-invocable: false
|
|
6
|
+
allowed-tools: Read, Grep, Glob, Edit, Write, Bash
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Apex Async Patterns
|
|
10
|
+
|
|
11
|
+
Implementation guidance for asynchronous Apex. Covers when to use each pattern and how to implement it correctly. Governor limit numbers and hard rules live in the referenced files and `sf-apex-constraints`.
|
|
12
|
+
|
|
13
|
+
Reference: @../_reference/ASYNC_PATTERNS.md
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## When to Use
|
|
18
|
+
|
|
19
|
+
- When synchronous Apex hits governor limits and needs a separate transaction
|
|
20
|
+
- When making HTTP callouts from trigger contexts
|
|
21
|
+
- When processing millions of records that exceed single-transaction limits
|
|
22
|
+
- When scheduling recurring Apex jobs on a cron-like schedule
|
|
23
|
+
- When decoupling event publishers from subscribers using Platform Events
|
|
24
|
+
- When deciding between `@future`, Queueable, Batch, Schedulable, or Platform Events
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Choosing the Right Pattern
|
|
29
|
+
|
|
30
|
+
| Requirement | Pattern |
|
|
31
|
+
|---|---|
|
|
32
|
+
| Simple async with no sObject params | `@future` |
|
|
33
|
+
| Need to pass sObjects or collections | `Queueable` |
|
|
34
|
+
| Need callouts from trigger context | `@future(callout=true)` |
|
|
35
|
+
| Need callouts with complex state | `Queueable + Database.AllowsCallouts` |
|
|
36
|
+
| Processing millions of records | `Batch Apex` |
|
|
37
|
+
| Need state across batches | `Batch Apex + Database.Stateful` |
|
|
38
|
+
| Run on a schedule | `Schedulable` (wraps Batch or Queueable) |
|
|
39
|
+
| Decouple publisher from subscriber | `Platform Events` |
|
|
40
|
+
| Chain jobs with delay | `Queueable + AsyncOptions` |
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## @future Methods
|
|
45
|
+
|
|
46
|
+
The simplest async mechanism. Runs in a separate transaction with its own governor limits.
|
|
47
|
+
|
|
48
|
+
```apex
|
|
49
|
+
public class ExternalDataSync {
|
|
50
|
+
|
|
51
|
+
@future(callout=true)
|
|
52
|
+
public static void syncAccountToERP(Id accountId) {
|
|
53
|
+
Account acc = [
|
|
54
|
+
SELECT Id, Name, BillingCity, AnnualRevenue
|
|
55
|
+
FROM Account WHERE Id = :accountId LIMIT 1
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
HttpRequest req = new HttpRequest();
|
|
59
|
+
req.setEndpoint('callout:ERP_System/accounts');
|
|
60
|
+
req.setMethod('POST');
|
|
61
|
+
req.setHeader('Content-Type', 'application/json');
|
|
62
|
+
req.setBody(JSON.serialize(new ERPAccountPayload(acc)));
|
|
63
|
+
|
|
64
|
+
HttpResponse res = new Http().send(req);
|
|
65
|
+
if (res.getStatusCode() != 200) {
|
|
66
|
+
logSyncError(accountId, res.getStatusCode(), res.getBody());
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### @future Constraints
|
|
73
|
+
|
|
74
|
+
- **No sObject parameters** — pass primitive types (Id, String) or serialized JSON. sObjects may change between enqueue and execution.
|
|
75
|
+
- **No chaining** — calling `@future` from another `@future` throws a runtime exception.
|
|
76
|
+
- **50 per transaction** — governor limit on future method invocations.
|
|
77
|
+
- **No return value** — fire-and-forget only.
|
|
78
|
+
- **Execution order not guaranteed**.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Queueable Apex
|
|
83
|
+
|
|
84
|
+
More powerful than `@future`. Supports sObject parameters, chaining, and monitoring via `AsyncApexJob`.
|
|
85
|
+
|
|
86
|
+
### Basic Queueable
|
|
87
|
+
|
|
88
|
+
```apex
|
|
89
|
+
public class AccountEnrichmentJob implements Queueable {
|
|
90
|
+
|
|
91
|
+
private final List<Account> accounts;
|
|
92
|
+
|
|
93
|
+
public AccountEnrichmentJob(List<Account> accounts) {
|
|
94
|
+
this.accounts = accounts;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public void execute(QueueableContext context) {
|
|
98
|
+
List<Account> toUpdate = new List<Account>();
|
|
99
|
+
for (Account acc : accounts) {
|
|
100
|
+
if (acc.AnnualRevenue != null && acc.NumberOfEmployees != null
|
|
101
|
+
&& acc.NumberOfEmployees > 0) {
|
|
102
|
+
toUpdate.add(new Account(
|
|
103
|
+
Id = acc.Id,
|
|
104
|
+
Revenue_Per_Employee__c = acc.AnnualRevenue / acc.NumberOfEmployees
|
|
105
|
+
));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (!toUpdate.isEmpty()) update toUpdate;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Enqueue
|
|
113
|
+
System.enqueueJob(new AccountEnrichmentJob(accounts));
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Queueable with Callouts
|
|
117
|
+
|
|
118
|
+
Implement `Database.AllowsCallouts` alongside `Queueable`.
|
|
119
|
+
|
|
120
|
+
```apex
|
|
121
|
+
public class ContactDataEnrichmentJob implements Queueable, Database.AllowsCallouts {
|
|
122
|
+
private final Set<Id> contactIds;
|
|
123
|
+
|
|
124
|
+
public ContactDataEnrichmentJob(Set<Id> contactIds) {
|
|
125
|
+
this.contactIds = contactIds;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public void execute(QueueableContext context) {
|
|
129
|
+
// Query, callout, update pattern
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Chaining Queueable Jobs
|
|
135
|
+
|
|
136
|
+
Use chaining to process large data sets across multiple transactions. Use WHERE clauses to naturally shrink the result set instead of OFFSET (which has a 2,000-row hard limit).
|
|
137
|
+
|
|
138
|
+
```apex
|
|
139
|
+
public class DataMigrationChainJob implements Queueable {
|
|
140
|
+
|
|
141
|
+
private static final Integer BATCH_SIZE = 200;
|
|
142
|
+
|
|
143
|
+
public void execute(QueueableContext context) {
|
|
144
|
+
List<Legacy_Record__c> batch = [
|
|
145
|
+
SELECT Id, Legacy_Field__c
|
|
146
|
+
FROM Legacy_Record__c
|
|
147
|
+
WHERE Migrated__c = false
|
|
148
|
+
ORDER BY CreatedDate
|
|
149
|
+
LIMIT :BATCH_SIZE
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
if (batch.isEmpty()) return; // Migration complete
|
|
153
|
+
|
|
154
|
+
processBatch(batch);
|
|
155
|
+
|
|
156
|
+
// Chain next job — WHERE Migrated__c = false naturally shrinks each iteration
|
|
157
|
+
System.enqueueJob(new DataMigrationChainJob());
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### AsyncOptions
|
|
163
|
+
|
|
164
|
+
```apex
|
|
165
|
+
// Delay execution by 5 minutes
|
|
166
|
+
System.AsyncOptions opts = new System.AsyncOptions();
|
|
167
|
+
opts.minimumQueueableDelayInMinutes = 5;
|
|
168
|
+
System.enqueueJob(new MyQueueableJob(data), opts);
|
|
169
|
+
|
|
170
|
+
// Duplicate prevention with a unique key
|
|
171
|
+
System.AsyncOptions opts2 = new System.AsyncOptions();
|
|
172
|
+
opts2.duplicateSignature = 'account-sync-' + accountId;
|
|
173
|
+
System.enqueueJob(new AccountSyncJob(accountId), opts2);
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Batch Apex
|
|
179
|
+
|
|
180
|
+
For processing large data volumes (millions of records) that exceed single-transaction limits.
|
|
181
|
+
|
|
182
|
+
### Basic Batch
|
|
183
|
+
|
|
184
|
+
```apex
|
|
185
|
+
public class AccountAnnualReviewBatch
|
|
186
|
+
implements Database.Batchable<SObject>, Database.Stateful {
|
|
187
|
+
|
|
188
|
+
private Integer processedCount = 0;
|
|
189
|
+
private List<String> errors = new List<String>();
|
|
190
|
+
|
|
191
|
+
public Database.QueryLocator start(Database.BatchableContext bc) {
|
|
192
|
+
return Database.getQueryLocator([
|
|
193
|
+
SELECT Id, Name, AnnualRevenue, Last_Annual_Review__c, OwnerId
|
|
194
|
+
FROM Account
|
|
195
|
+
WHERE Type = 'Customer'
|
|
196
|
+
AND (Last_Annual_Review__c = null
|
|
197
|
+
OR Last_Annual_Review__c < LAST_N_DAYS:365)
|
|
198
|
+
]);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
public void execute(Database.BatchableContext bc, List<Account> scope) {
|
|
202
|
+
// Process scope — each execute() is its own transaction
|
|
203
|
+
// Default scope = 200 records
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
public void finish(Database.BatchableContext bc) {
|
|
207
|
+
// Cleanup and notifications
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Execute (default scope of 200)
|
|
212
|
+
Database.executeBatch(new AccountAnnualReviewBatch());
|
|
213
|
+
|
|
214
|
+
// Custom scope (smaller for complex processing or callouts)
|
|
215
|
+
Database.executeBatch(new AccountAnnualReviewBatch(), 50);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Batch with Callouts
|
|
219
|
+
|
|
220
|
+
Implement `Database.AllowsCallouts` and set scope = 1 when each callout is per-record (each execute() is limited to 100 callouts).
|
|
221
|
+
|
|
222
|
+
```apex
|
|
223
|
+
public class SingleRecordCalloutBatch
|
|
224
|
+
implements Database.Batchable<SObject>, Database.AllowsCallouts {
|
|
225
|
+
// scope = 1 in executeBatch call
|
|
226
|
+
}
|
|
227
|
+
Database.executeBatch(new SingleRecordCalloutBatch(), 1);
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Schedulable Apex
|
|
233
|
+
|
|
234
|
+
Runs Apex on a schedule. Best practice: schedulable should only coordinate, not do heavy work.
|
|
235
|
+
|
|
236
|
+
```apex
|
|
237
|
+
public class WeeklyReportScheduler implements Schedulable {
|
|
238
|
+
public void execute(SchedulableContext sc) {
|
|
239
|
+
Database.executeBatch(new WeeklyReportBatch(), 200);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Schedule
|
|
244
|
+
String cronExp = '0 0 6 ? * MON'; // Every Monday at 6:00 AM
|
|
245
|
+
System.schedule('Weekly Report - Monday 6AM', cronExp, new WeeklyReportScheduler());
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Cron Expression Reference
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
0 0 2 * * ? — Daily at 2:00 AM
|
|
252
|
+
0 0 9 ? * MON-FRI — Weekdays at 9:00 AM
|
|
253
|
+
0 0 0 1 * ? * — First day of every month at midnight
|
|
254
|
+
0 30 8 ? * SAT — Every Saturday at 8:30 AM
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Platform Events
|
|
260
|
+
|
|
261
|
+
Decouple publishers from subscribers. Subscribers run in their own transaction.
|
|
262
|
+
|
|
263
|
+
### Publishing
|
|
264
|
+
|
|
265
|
+
```apex
|
|
266
|
+
List<Order_Status_Change__e> events = new List<Order_Status_Change__e>();
|
|
267
|
+
for (Order__c order : orders) {
|
|
268
|
+
events.add(new Order_Status_Change__e(
|
|
269
|
+
Order_Id__c = order.Id,
|
|
270
|
+
New_Status__c = newStatus,
|
|
271
|
+
Changed_By__c = UserInfo.getUserId(),
|
|
272
|
+
Timestamp__c = Datetime.now()
|
|
273
|
+
));
|
|
274
|
+
}
|
|
275
|
+
List<Database.SaveResult> results = EventBus.publish(events);
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
> By default, high-volume platform events use "publish after commit" behavior. To publish immediately regardless of transaction outcome, configure the event's Publish Behavior to "Publish Immediately" in Setup.
|
|
279
|
+
|
|
280
|
+
### Subscribing via Trigger
|
|
281
|
+
|
|
282
|
+
```apex
|
|
283
|
+
trigger OrderStatusChangeTrigger on Order_Status_Change__e (after insert) {
|
|
284
|
+
for (Order_Status_Change__e event : Trigger.new) {
|
|
285
|
+
// Process event — runs in its own transaction
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### High-Volume Events and ReplayId
|
|
291
|
+
|
|
292
|
+
```apex
|
|
293
|
+
trigger HighVolumeEventTrigger on Analytics_Event__e (after insert) {
|
|
294
|
+
// Set resume checkpoint for retry-after-failure
|
|
295
|
+
EventBus.TriggerContext.currentContext().setResumeCheckpoint(
|
|
296
|
+
Trigger.new[Trigger.new.size() - 1].ReplayId
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Testing Async Apex
|
|
304
|
+
|
|
305
|
+
`Test.startTest()` / `Test.stopTest()` forces @future, Queueable, and Batch jobs to execute synchronously. Platform events are also delivered synchronously within the test boundary.
|
|
306
|
+
|
|
307
|
+
```apex
|
|
308
|
+
@isTest
|
|
309
|
+
static void testBatchUpdatesReviewDate() {
|
|
310
|
+
// Insert test data
|
|
311
|
+
Test.startTest();
|
|
312
|
+
Database.executeBatch(new AccountAnnualReviewBatch(), 200);
|
|
313
|
+
Test.stopTest(); // All batch methods run synchronously
|
|
314
|
+
// Assert results
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Related
|
|
321
|
+
|
|
322
|
+
- **Agents**: `sf-review-agent`, `sf-apex-agent` — For interactive guidance
|
|
323
|
+
|
|
324
|
+
### Guardrails
|
|
325
|
+
|
|
326
|
+
- `sf-apex-constraints` — Governs limits, bulkification rules, and naming conventions for all Apex code including async
|