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? Sehen Sie sich dieses Video an, das zur Serie "Trail Together" auf Trailhead Live gehört.
(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
Apex-Methoden mit der @future-Kennzeichnung (die im weiteren Verlauf dieses Moduls als “Future-Methoden” bezeichnet werden) werden asynchron in einem separaten Thread ausgeführt, zu einem späteren Zeitpunkt, wenn Systemressourcen verfügbar werden.
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. Asynchrone Verarbeitung bietet den Vorteil, den Benutzer nicht am Ausführen anderer Vorgänge zu hindern. Ferner stellt sie dem Prozess höhere Obergrenzen für die Ausführung zur Verfügung. 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-Methode oder die
Queueable-Schnittstelle verwenden. Durch einen Callout in einem Auslöser würde andernfalls die Datenbankverbindung für die gesamte Lebensdauer des Callouts aufrecht erhalten und das ist in einer mandantenfähigen Umgebung sehr kostspielig. - 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 weisen nochmals darauf hin, weil Sie dies wirklich unbedingt beachten müssen: Future-Methoden werden nicht mit Sicherheit in derselben Reihenfolge ausgeführt, in der sie aufgerufen wurden. 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 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 wird. 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. Der synchrone Aufruf fügt außerdem einen Datensatz in ein benutzerdefiniertes Protokollobjekt ein, um den Status des Callouts nachzuverfolgen.
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
@futuremü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. Zum Vermeiden rekursiver Future-Methodenaufrufe sollten Sie System.isFuture() verwenden, das
truezurückgibt, wenn der aktuell ausgeführte Code von Code aufgerufen wird, der in einer Future-Methode enthalten ist. - Die Methoden
getContent()undgetContentAsPDF()dürfen in Methoden mit der Anmerkung@futurenicht 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. Mehr dazu erfahren Sie unter Execution Governors and Limits.
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: Isolation of Test Data from Organization Data in Unit Tests
