
Inline adoc files when they are included exactly once. Also fix language tags because this inlining gives us better information on what language the code is written in.
91 lines
3.0 KiB
Plaintext
91 lines
3.0 KiB
Plaintext
== Why is this an issue?
|
||
|
||
There are three limits related to methods annotated with the ``++@future++`` keyword:
|
||
|
||
* There is a maximum number of ``++@future++`` calls allowed per transaction.
|
||
* There is a maximum number of ``++@future++`` calls allowed per organization and per a 24-hour period.
|
||
* Salesforce protects its infrastructure from organizations calling too many ``++@future++`` methods: if more than 2000 ``++@future++`` requests are queued, any additional request https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_invoking_future_methods.htm[will be delayed].
|
||
|
||
Thus it is a best practice to avoid calling ``++@future++`` methods in loops and instead call it once with all the necessary data.
|
||
|
||
|
||
See https://developer.salesforce.com/docs/atlas.en-us.222.0.apexcode.meta/apexcode/apex_gov_limits.htm[Execution Governors and Limits] for the exact number of ``++@future++`` calls allowed in each context.
|
||
|
||
|
||
This rule raises an issue when a method annotated with the ``++@future++`` keyword is called in a loop.
|
||
|
||
|
||
=== Noncompliant code example
|
||
|
||
[source,apex]
|
||
----
|
||
public class FutureClass {
|
||
@future
|
||
public static void processTaskFuture(ID taskId) {
|
||
Task task = [SELECT Id, Subject FROM Task WHERE Task.Id = :taskId];
|
||
task.Subject = 'new task subject';
|
||
update task;
|
||
}
|
||
|
||
public static void updateUserTasks(ID ownerID) {
|
||
List<Task> tasks = [SELECT Id, Subject FROM Task WHERE Task.ownerid = :ownerID];
|
||
for (Task task: tasks) {
|
||
processTaskFuture(task.Id); // Noncompliant
|
||
}
|
||
}
|
||
----
|
||
|
||
|
||
=== Compliant solution
|
||
|
||
[source,apex]
|
||
----
|
||
public class FutureClass {
|
||
@future
|
||
public static void processTasksFuture(List<ID> taskIds) {
|
||
List<Task> tasks = [SELECT Id, Subject FROM Task WHERE Task.Id IN :taskIds];
|
||
for (Task task : tasks) {
|
||
task.Subject = 'new task subject';
|
||
}
|
||
update tasks;
|
||
}
|
||
|
||
public static void updateUserTasks(ID ownerID) {
|
||
List<Task> tasks = [SELECT Id, Subject FROM Task WHERE Task.ownerid = :ownerID];
|
||
List<Id> ids = new List<ID>();
|
||
for (Task task: tasks) {
|
||
ids.add(task.Id);
|
||
}
|
||
processTasksFuture(ids);
|
||
}
|
||
----
|
||
|
||
|
||
== Resources
|
||
|
||
* https://developer.salesforce.com/page/Apex_Code_Best_Practices[Apex Code Best Practices]
|
||
* https://developer.salesforce.com/docs/atlas.en-us.222.0.apexcode.meta/apexcode/apex_gov_limits.htm[Execution Governors and Limits]
|
||
* https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_invoking_future_methods.htm[Future Methods]
|
||
* https://trailhead.salesforce.com/content/learn/modules/asynchronous_apex/async_apex_future_methods[Use Future Methods]
|
||
|
||
ifdef::env-github,rspecator-view[]
|
||
|
||
'''
|
||
== Implementation Specification
|
||
(visible only on this page)
|
||
|
||
=== Message
|
||
|
||
Move this "@future" method call out of the loop
|
||
|
||
|
||
=== Highlighting
|
||
|
||
Primary location: the call to the @future method.
|
||
|
||
|
||
Secondary location: the "do", "while" or "for" keyword of the loop.
|
||
|
||
|
||
endif::env-github,rspecator-view[]
|