Verwenden von Future-Methoden
Lernziele
Nachdem Sie diese Lektion abgeschlossen haben, haben Sie Folgendes gelernt:
- Zeitpunkt für die Verwendung von Future-Methoden
- Einschränkungen bei der Verwendung von Future-Methoden
- Verwenden von Future-Methoden für Callouts
- Future-Methoden – bewährte Vorgehensweisen
Mit Trail Together einem Dozenten folgen
Möchten Sie bei diesem Schritt einem Dozenten folgen? Schauen Sie sich dieses Video an, das Teil der Reihe "Trail Together" auf Trailhead Live ist.
(Dieser Clip beginnt bei Minute 09:39, für den Fall, dass Sie zurückspringen und den Anfang des Schritts noch einmal sehen möchten.)
Future-Apex
Future-Apex wird verwendet, um Prozesse zu einem späteren Zeitpunkt in einem separaten Thread auszuführen, wenn Systemressourcen verfügbar werden.
Hinweis: Technisch gesehen, verwenden Sie die Anmerkung @future
zur Kennzeichnung von Methoden, die asynchron ausgeführt werden. Da jedoch "mit der Anmerkung @future
gekennzeichnete Methoden" als Bezeichnung ziemlich umständlich ist, werden sie gemeinhin als "Future-Methoden" bezeichnet und genau das tun wir auch im Rest dieses Moduls.
Bei Verwendung der synchronen Verarbeitung erfolgen alle Methodenaufrufe aus dem gleichen Thread, der auch den Apex-Code ausführt, und es ist keine weitere Verarbeitung möglich, bis der Prozess abgeschlossen ist. Sie können Future-Methoden für jeden Vorgang verwenden, den Sie asynchron in seinem eigenen Thread ausführen möchten. Dies hat zum einen den Vorteil, dass der Benutzer nicht an der Durchführung anderer Vorgänge gehindert wird, und zum anderen gelten für den Prozess höhere Obergrenzen für die Ausführung. Es profitieren also alle Seiten von der asynchronen Verarbeitung.
Future-Methoden werden meist für folgende Zwecke verwendet:
- Callouts an externe Webservices. Wenn Sie Callouts von einem Auslöser aus oder nach der Durchführung eines DML-Vorgangs durchführen, müssen Sie eine Future- oder Queueable-Methode verwenden. Durch einen Callout in einem Auslöser würde die Datenbankverbindung für die gesamte Lebensdauer des Callouts aufrecht erhalten und das ist in einer mandantenfähigen Umgebung ein Tabu.
- Vorgänge, die Sie in ihrem eigenen Thread ausführen möchten, wenn der Zeitpunkt günstig ist, wie z. B. eine ressourcenintensive Berechnung oder Datensatzverarbeitung.
- Isolieren von DML-Vorgängen für verschiedene sObject-Typen, um den Mixed DML-Fehler zu vermeiden. Dieser Anwendungsfall tritt jedoch eher selten auf. Weitere Einzelheiten finden Sie unter sObjects That Cannot Be Used Together in DML Operations.
Syntax von Future-Methoden
Future-Methoden müssen statische Methoden sein und dürfen nur einen void-Typ zurückgeben. Die angegebenen Parameter müssen primitive Datentypen oder Sammlungen primitiver Datentypen sein. Vor allem dürfen bei Future-Methoden keine standardmäßigen oder benutzerdefinierten Objekte als Argumente angegeben werden. Im allgemeinen wird der Methode eine List
(Liste) mit Datensatz-IDs übergeben, die asynchron verarbeitet werden sollen.
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 } }
Hier muss unbedingt darauf hingewiesen werden, dass es nicht garantiert ist, dass Future-Methoden in derselben Reihenfolge ausgeführt werden, in der sie aufgerufen wurden. Wir sagen es noch einmal, denn es ist wichtig, dass Sie sich daran erinnern: Future- Methoden werden nicht garantiert in der gleichen Reihenfolge ausgeführt, in der sie aufgerufen werden. Bei der Verwendung von Future-Methoden besteht zudem die Möglichkeit, dass zwei Future-Methoden gleichzeitig ausgeführt werden. Dies kann zu einer Datensatzsperre und einem unschönen Laufzeitfehler führen, wenn die beiden Methoden denselben Datensatz aktualisieren.
Callout-Beispielcode
Wenn Sie einen Webservice-Callout zu einem externen Service oder einer API durchführen möchten, erstellen Sie eine Apex-Klasse mit einer Future-Methode, die mit (callout=true)
gekennzeichnet ist. Die nachfolgende Klasse enthält zwei Methoden: eine für die synchrone und eine für die asynchrone Callout-Durchführung, sofern synchrone Callouts nicht zulässig sind. Wir fügen einen Datensatz in ein benutzerdefiniertes Protokollobjekt ein, um den Status des Callouts nachzuverfolgen. Warum? Weil Protokollieren einfach immer Spaß macht!
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; } }
Testklassen
Das Testen von Future-Methoden unterscheidet sich etwas vom normalen Apex-Testen. Zum Testen von Future-Methoden fügen Sie Ihren Testcode zwischen die Testmethoden startTest()
und stopTest()
ein. Das System sammelt alle asynchronen Aufrufe, die nach startTest()
durchgeführt werden. Wenn stopTest()
ausgeführt wird, werden alle diese gesammelten, asynchronen Prozesse synchron ausgeführt. Sie können dann sicherstellen, dass der asynchrone Aufruf richtig funktioniert hat.
Hier sehen Sie unsere simulierte Callout-Klasse, die beim Testen verwendet wird. Das Apex-Test-Framework nutzt diese "simulierte" Antwort, anstelle den tatsächlichen Callout an den REST API-Endpunkt durchzuführen.
@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; } }
Die Testklasse enthält eine einzige Testmethode (testSendSms()
in diesem Beispiel), die sowohl die asynchrone als auch die synchrone Methode testet, da die asynchrone die synchrone Methode aufruft.
@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); } }
Bewährte Vorgehensweisen
Da bei jedem Aufruf einer Future-Methode eine Anforderung zur asynchronen Warteschlange hinzugefügt wird, sollten Sie Designmuster vermeiden, bei denen in einem kurzen Zeitraum viele Future-Anforderungen hinzugefügt werden. Wenn Ihr Design das Potenzial hat, 2000 oder mehr Anforderungen gleichzeitig hinzuzufügen, könnten Anforderungen aufgrund der Datenflusssteuerung verzögert werden. Hier sind einige bewährte Vorgehensweisen, die Sie im Hinterkopf behalten sollten:
- Stellen Sie sicher, dass Future-Methoden so schnell wie möglich ausgeführt werden.
- Versuchen Sie bei der Verwendung von Webservice-Callouts, alle Callouts innerhalb derselben Future-Methode zu bündeln, anstatt für jeden Callout eine separate Future-Methode zu verwenden.
- Führen Sie gründliche Tests in der gewünschten Skalierung durch. Testen Sie, ob ein Auslöser, der die
@future
-Aufrufe in die Warteschlange einreiht, eine Auslösersammlung von 200 Datensätzen verarbeiten kann. Damit können Sie die Wahrscheinlichkeit von Verzögerungen für das Design mit dem aktuellen und künftigen Volumen feststellen. - Ziehen Sie die Verwendung von Batch-Apex anstelle von Future-Methoden für die asynchrone Verarbeitung großer Datensatzmengen in Erwägung. Dies ist effizienter als die Erstellung einer Future-Anforderung für jeden Datensatz.
Wichtige Punkte
Future-Methoden sind ein mächtiges Tool, doch große "Macht" bedeutet auch große Verantwortung. Hier sind einige Punkte, die Sie bei der Arbeit mit Future-Methoden beachten sollten:
- Methoden mit der Anmerkung
@future
müssen statische Methoden sein und dürfen nur einen void-Typ zurückgeben. - Die angegebenen Parameter müssen primitive Datentypen oder Sammlungen primitiver Datentypen sein. Bei Future-Methoden dürfen keine Objekte als Argumente angegeben werden.
- Future-Methoden werden nicht zwingend in der Reihenfolge ausgeführt, in der sie aufgerufen werden. Es besteht zudem die Möglichkeit, dass zwei Future-Methoden gleichzeitig ausgeführt werden. Dies kann zu einer Datensatzsperre führen, wenn die beiden Methoden denselben Datensatz aktualisieren.
- Future-Methoden können weder in Visualforce-Steuerfeldern in
getMethodName()
odersetMethodName()
noch im Konstruktor verwendet werden. - Eine Future-Methode kann nicht innerhalb einer Future-Methode aufgerufen werden. Sie können auch nicht während der Ausführung einer Future-Methode einen Auslöser aufrufen, der eine Future-Methode aufruft. Weitere Informationen zur Vermeidung rekursiver Aufrufe von Future-Methode finden Sie unter dem im Abschnitt "Ressourcen" angegebenen Link.
- Die Methoden
getContent()
undgetContentAsPDF()
dürfen in Methoden mit der Anmerkung@future
nicht verwendet werden. - Pro Apex-Aufruf dürfen maximal 50 Future-Methoden aufgerufen werden. Zusätzlich gibt es noch ein Limit für die Anzahl der Aufrufe innerhalb von 24 Stunden. Weitere Informationen zu Limits finden Sie unter dem unten angegebenen Link.
Ressourcen
- Apex Developer Guide: Future-Methoden
- Apex Reference Guide: System.isFuture()-Methode
- Apex Developer Guide: sObjects That Cannot Be Used Together in DML Operations
- Apex Developer Guide: Execution Governors and Limits
- Apex Developer Guide: Isolation of Test Data from Organization Data in Unit Tests