Utilisation de méthodes futures
Objectifs de formation
Dans cette unité, vous allez découvrir :
- Quand utiliser des méthodes futures
- Les limitations d’utilisation de méthodes futures
- Comment utiliser des méthodes futures pour des appels externes
- Les meilleures pratiques d’utilisation de méthodes futures
Vidéo de démonstration Trail Together
Vous souhaitez être guidé pas à pas pendant que vous travaillez sur cette étape ? Regardez cette vidéo qui fait partie de la série Trail Together sur Trailhead Live.
(Ce clip commence à 9 min 39 s, au cas où vous voudriez revenir en arrière et regarder à nouveau le début de l’étape.)
Apex futur
Un code Apex futur est utilisé pour exécuter des processus ultérieurement dans un thread distinct, lorsque les ressources système sont disponibles.
Remarque : Techniquement, vous utilisez l’annotation @future
pour identifier les méthodes exécutées de façon asynchrone. Cependant, l’expression « méthode identifiée avec l’annotation @future
» est laborieuse. Par conséquent, elles sont communément appelées « méthodes futures », expression que nous allons employer dans ce module.
Lors de l’utilisation d’un traitement synchrone, tous les appels de méthode proviennent du même thread qui exécute le code Apex, et aucun traitement supplémentaire ne peut être effectué avant la fin du processus. Vous pouvez utiliser des méthodes futures pour toute opération que vous souhaitez exécuter de façon asynchrone dans son propre thread. Avec les méthodes futures, l’utilisateur peut exécuter d’autres opérations, et vous pouvez définir des limitations du gouverneur et d’exécution supérieures pour le processus. Le traitement asynchrone satisfait tout le monde.
Les méthodes futures sont généralement utilisées pour les opérations suivantes :
- Des appels externes à des services Web externes. Si vous effectuez des appels externes à partir d’un déclencheur ou après l’exécution d’une opération DML, vous devez utiliser une méthode future ou pour file d'attente. Un appel externe dans un déclencheur garderait la connexion à la base de données ouverte pendant la durée de vie de l’appel externe, ce qui est interdit dans un environnement mutualisé.
- Les opérations que vous souhaitez exécuter dans leur propre thread, lorsque les conditions sont favorables, par exemple un calcul ou un traitement d’enregistrements qui mobilise des ressources importantes.
- L’isolation des opérations DML sur différents types de sObject afin d’éviter l’erreur d’opérations DML mixtes. Il s’agit d’un cas extrême, mais vous pouvez parfois rencontrer cette erreur. Pour plus informations, reportez-vous à sObjects That Cannot Be Used Together in DML Operations (en anglais).
Syntaxe d'une méthode future
Les méthodes futures sont des méthodes statiques qui peuvent renvoyer uniquement un type void. Les paramètres spécifiés doivent être des types de données primitifs ou des collections de types de données primitifs. En particulier, les méthodes futures ne peuvent pas accepter des objets standard ou personnalisés en tant qu’arguments. Un modèle courant consiste à transmettre à la méthode une List
(liste) d’ID d’enregistrement que vous souhaitez traiter de façon asynchrone.
public class SomeClass { @future public static void someFutureMethod(List<Id> recordIds) { List<Account> accounts = [Select Id, Name from Account Where Id IN :recordIds]; // process account records to do awesome stuff } }
Il est important de noter que les méthodes futures ne sont pas nécessairement exécutées dans l’ordre dans lequel elles sont appelées. Nous ne le répéterons jamais assez : les méthodes futures ne sont pas nécessairement exécutées dans l’ordre dans lequel elles sont appelées. Lors de l’utilisation de méthodes futures, il se peut également que deux méthodes futures soient exécutées simultanément, ce qui peut entraîner un verrouillage d’enregistrement et une erreur d’exécution si les deux méthodes mettent à jour le même enregistrement.
Exemple de code d’appel externe
Pour exécuter un appel externe de service Web à un service externe ou une API, vous créez une classe Apex avec une méthode future marquée avec (callout=true)
. La classe ci-dessous contient les méthodes d’exécution de l’appel de façon synchrone et asynchrone lorsque les appels externes ne sont pas autorisés. Nous insérons un enregistrement dans un objet de journal personnalisé pour suivre le statut de l’appel externe, simplement parce que la consignation est toujours intéressante !
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; } }
Classes de test
Le test de méthodes futures est légèrement différent que le test Apex classique. Pour tester des méthodes futures, insérez votre code test entre les méthodes de test startTest()
et stopTest()
. Le système collecte tous les appels asynchrones effectués après startTest()
. Lorsque stopTest()
est exécuté, tous ces processus asynchrones collectés sont exécutés de façon synchrone. Vous pouvez ensuite affirmer que l’appel asynchrone fonctionne correctement.
Notre classe d’appel externe fictive pour le test se présente comme suit. L’infrastructure de test Apex utilise cette réponse fictive au lieu de transmettre l’appel externe au point de terminaison de l’API REST.
@isTest public class SMSCalloutMock implements HttpCalloutMock { public 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; } }
La classe de test contient une seule méthode de test (dans notre exemple, testSendSms()
). Elle teste la méthode asynchrone et la méthode synchrone, la première appelant la dernière.
@IsTest private class Test_SMSUtils { @IsTest private static void testSendSms() { Test.setMock(HttpCalloutMock.class, new SMSCalloutMock()); Test.startTest(); SMSUtils.sendSMSAsync('111', '222', 'Greetings!'); Test.stopTest(); // runs callout and check results List<SMS_Log__c> logs = [select msg__c from SMS_Log__c]; System.assertEquals(1, logs.size()); System.assertEquals('success', logs[0].msg__c); } }
Meilleures pratiques
L’invocation de chaque méthode future ajoute une requête à la file d’attente asynchrone. Par conséquent, évitez les modèles de conception qui ajoutent un nombre important de requêtes futures sur une courte période. Si votre conception peut ajouter 2000 requêtes ou plus à la fois, les requêtes peuvent être retardées en raison du contrôle du flux. Tenez compte des pratiques recommandées ci-dessous :
- Assurez-vous que les méthodes futures sont exécutées aussi rapidement que possibles.
- Si vous utilisez des appels externes de service Web, essayez de regrouper tous les appels externes de la même méthode future au lieu d’utiliser une méthode future séparée pour chaque appel externe.
- Effectuez des tests complets à l’échelle. Effectuez un test pour déterminer si un déclencheur mettant en file d’attente des appels
@future
peut gérer une collection de déclencheur comportant 200 enregistrements. Vous pouvez ainsi déterminer si la conception des volumes actuels et futurs entraîne des délais. - Utilisez un code Apex par lot plutôt que des méthodes futures pour traiter simultanément un grand nombre d’enregistrements. Cette solution est plus efficace que la création d’une requête future pour chaque enregistrement.
À retenir
Les méthodes futures sont très efficaces, mais leur puissance doit être contrôlée. Lors de l’utilisation de méthodes futures, tenez compte des points suivants :
- Les méthodes munies de l’annotation
@future
doivent être statiques et ne peuvent renvoyer qu’un type void. - Les paramètres spécifiés doivent être des types de données primitifs ou des collections de types de données primitifs. Les méthodes futures ne peuvent pas accepter des objets en tant qu’arguments.
- L’ordre d’exécution des méthodes futures ne correspond pas nécessairement à l’ordre dans lequel elles sont appelées. En outre, deux méthodes futures peuvent être exécutées simultanément, ce qui peut entraîner un verrouillage d’enregistrement si les deux méthodes mettent à jour le même enregistrement.
- Les méthodes futures ne peuvent pas être utilisées dans des contrôleurs Visualforce dans
getMethodName()
,setMethodName()
ou dans le constructeur. - Vous ne pouvez pas appeler une méthode future à partir d’une méthode future. Vous ne pouvez pas non plus invoquer un déclencheur qui appelle une méthode future tout en exécutant une méthode future. Pour empêcher les appels de méthode future récursifs, suivez le lien « Preventing Recursive Future Method Calls in Salesforce » dans la section Ressources.
- Les méthodes
getContent()
etgetContentAsPDF()
ne peuvent pas être utilisées dans des méthodes comportant l’annotation@future
. - Vous êtes limité(e) à 50 appels futurs par invocation Apex avec une limite supplémentaire en nombre d’appels par période de 24 heures. Pour plus d’informations sur ces limitations, suivez le lien ci-dessous.
Ressources
- Apex Developer Guide: Méthodes futures
- Guide du développeur Apex : Méthode System.isFuture()
- Guide du développeur Apex : sObjects ne pouvant être utilisés ensemble dans des opérations DML
- Apex Developer Guide: Execution Governors and Limits
- Apex Developer Guide: Isolation de données de test à partir de données d'organisation dans des tests unitaires