Future Apex is used to run processes in a separate thread, at a later time when system resources become available.
You use the @future annotation to identify methods that run asynchronously.
Future methods are typically used for:
- Callouts to external Web services. If you are making callouts from a trigger or after performing a DML operation, you must use a future or queueable method. A callout in a trigger would hold the database connection open for the lifetime of the callout and that is a “no-no” in a multitenant environment.
- Operations you want to run in their own thread, when time permits such as some sort of resource-intensive calculation or processing of records.
- Isolating DML operations on different sObject types to prevent the mixed DML error.
Syntax of Future Method :-
global class futureClass { @future public static void myFutureMethod(List recordIds) { List accounts = [Select Id, Name from Account Where Id IN :recordIds]; // process account records to do something } }
- Future method must be static and return type is void always.
- Parameters must be primitive data types, arrays of primitive data types, or collections of primitive data types.
- Future methods can’t take standard or custom objects as arguments.
- A common pattern is to pass the method a List of record IDs that you want to process asynchronously.
Note
The reason why objects can’t be passed as arguments to future methods is because the object can change between the time you call the method and the time that it actually executes. Remember, future methods are executed when system resources become available. In this case, the future method may have an old object value when it actually executes, which can cause all sorts of bad things to happen.
- Future methods are not guaranteed to execute in the same order as they are called.
- If you need this type of functionality then Queueable Apex might be a better solution.
Callout Using Future –
To make a Web service callout to an external service or API, you create an Apex class with a future method that is marked with (callout=true).
public class SMSUtils { // Call async from triggers, etc, where callouts are not permitted. @future(callout=true) public static void sendSMSAsync(String fromNbr, String toNbr, String m) { String results = sendSMS(fromNbr, toNbr, m); System.debug(results); } // Call from controllers, etc, for immediate processing public static String sendSMS(String fromNbr, String toNbr, String m) { // Calling 'send' will result in a callout String results = SmsMessage.send(fromNbr, toNbr, m); insert new SMS_Log__c(to__c=toNbr, from__c=fromNbr, msg__c=results); return results; } }
Test Class for Future Method Class –
To test future methods, enclose your test code between the startTest and stopTest test methods. The system collects all asynchronous calls made after the startTest. When stopTest is executed, all these collected asynchronous processes are then run synchronously. You can then assert that the asynchronous call operated properly.
Note : Test code cannot actually send callouts to external systems, so you’ll have to ‘mock’ the callout for test coverage.
@isTest global class SMSCalloutMock implements <strong>HttpCalloutMock</strong> { global HttpResponse respond(HttpRequest req) { // Create a fake response HttpResponse res = new HttpResponse(); res.setHeader('Content-Type', 'application/json'); res.setBody('{"status":"success"}'); res.setStatusCode(200); return res; } }
@IsTest private class Test_SMSUtils { @IsTest private static void testSendSms() { <strong>Test.setMock(HttpCalloutMock.class, new SMSCalloutMock());</strong> Test.startTest(); SMSUtils.sendSMSAsync('111', '222', 'Greetings!'); Test.stopTest(); // runs callout and check results List logs = [select msg__c from SMS_Log__c]; System.assertEquals(1, logs.size()); System.assertEquals('success', logs[0].msg__c); } }
Important Points –
- Methods with the future annotation must be static methods, and can only return a void type.
- The specified parameters must be primitive data types, arrays of primitive data types, or collections of primitive data types; future methods can’t take objects as arguments.
- Future methods won’t necessarily execute in the same order they are called. In addition, it’s possible that two future methods could run concurrently, which could result in record locking if the two methods were updating the same record.
- Future methods can’t be used in Visualforce controllers in getMethodName(), setMethodName(), nor in the constructor.
- You can’t call a future method from a future method. Nor can you invoke a trigger that calls a future method while running a future method.
- The getContent() and getContentAsPDF() methods can’t be used in methods with the future annotation.
- You’re limited to 50 future calls per Apex invocation, and there’s an additional limit on the number of calls in a 24-hour period. For more information on limits, see the link below.