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 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 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
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
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);
}