Skip to main content

Code reviews rule: Use of @future method in loop

Written by David Martin
Updated this week

Use of @future method in loop

Why is this an issue?

This rule identifies instances where a method annotated with @future is called inside a loop.

Salesforce imposes a strict governor limit on the number of future method invocations allowed in a single transaction (currently 50). Invoking a future method within a loop creates a high risk of exceeding this limit, which results in a System.LimitException: Too many future calls and causes the transaction to fail.

Even if the loop count is low, this pattern indicates a lack of bulkification, leading to inefficient processing and harder-to-maintain code.

Examples

Example of incorrect code: The following code calls the async method once for every record in the list.

public void processAccounts(List<Account> accounts) {
for (Account acc : accounts) {
// Violation: Calling a @future method inside a loop
doAsyncCallout(acc.Id);
}
}

@future(callout=true)
public static void doAsyncCallout(Id accountId) {
// Logic to process single account
}

Example of correct code: The following code bulkifies the operation by collecting IDs and making a single async call.

public void processAccounts(List<Account> accounts) {
Set<Id> accountIds = new Set<Id>();

for (Account acc : accounts) {
accountIds.add(acc.Id);
}

// Fix: Call the @future method once outside the loop
if (!accountIds.isEmpty()) {
doAsyncCallout(accountIds);
}
}

@future(callout=true)
public static void doAsyncCallout(Set<Id> accountIds) {
// Logic to process the list of accounts
}

How can I fix violations?

To fix this violation, you must bulkify the future method.

  1. Modify the @future method to accept a collection (e.g., List<Id>, Set<Id>, or List<String>) instead of a single primitive value. Note: Future methods cannot accept sObjects as arguments.

  2. Update the calling logic to iterate through the data, collect the necessary IDs or values into a list, and invoke the future method once after the loop finishes.

When should I disable this rule?

You may consider dismissing specific violations if you are strictly iterating over a bounded collection that is guaranteed to be small (e.g., a hardcoded list of 2 or 3 items) and you intentionally require separate asynchronous transactions for each item.

Resources

Did this answer your question?