== 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 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 taskIds) { List 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 tasks = [SELECT Id, Subject FROM Task WHERE Task.ownerid = :ownerID]; List ids = new List(); 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[]