Anti-Pattern: waitForComplete() im JavaScript-Code verwenden

Sie lesen gerade die Dokumentation zu Apigee und Apigee Hybrid.
Apigee Edge-Dokumentation aufrufen.

In der JavaScript-Richtlinie können Sie benutzerdefinierten Code hinzufügen, der im Kontext eines API-Proxy-Ablaufs ausgeführt wird. Beispielsweise kann der benutzerdefinierte Code in der JavaScript-Richtlinie verwendet werden, um:

  • Flussvariablen abzurufen und festzulegen
  • Benutzerdefinierte Logik auszuführen und Fehlerbehandlung durchzuführen
  • Daten aus Anfragen oder Antworten zu extrahieren
  • Back-End-Ziel-URL dynamisch zu bearbeiten
  • Header einer Anfrage oder Antwort dynamisch hinzuzufügen oder zu entfernen
  • Eine JSON-Antwort zu parsen

HTTP-Client

Eine leistungsstarke Funktion der JavaScript-Richtlinie ist der HTTP-Client. Der HTTP-Client (oder das httpClient-Objekt) kann für einen oder mehrere Aufrufe an Back-End- oder externe Dienste verwendet werden. Der HTTP-Client ist besonders dann nützlich, wenn mehrere externe Dienste aufgerufen werden müssen und die Antworten in einer einzigen API zusammengefasst werden müssen.

Beispiel für JavaScript-Code, der einen Back-End mit dem HTTP-Objekt „Client“ ausführt

var headers = {'X-SOME-HEADER' : 'some value' };
var myRequest = new Request("http://www.example.com","GET",headers);
var exchange = httpClient.send(myRequest);

Das httpClient-Objekt stellt zwei Methoden get und send bereit (send wird im obigen Beispielcode verwendet), um HTTP-Anfragen zu senden. Beide Methoden sind asynchron und geben ein exchange-Objekt zurück, bevor die tatsächliche HTTP-Anfrage abgeschlossen wird.

Die HTTP-Anfragen können einige Sekunden bis zu einigen Minuten dauern. Nach einer HTTP-Anfrage ist es wichtig zu wissen, wann sie abgeschlossen ist, damit die Antwort der Anfrage verarbeitet werden kann. Eine der häufigsten Methoden, um zu ermitteln, wann die HTTP-Anfrage abgeschlossen ist, besteht darin, die Methode waitForComplete() des exchange-Objekts aufzurufen.

waitForComplete()

Die Methode waitForComplete() pausiert den Thread, bis die HTTP-Anfrage abgeschlossen ist und eine Antwort (Erfolg/Fehler) zurückgegeben wird. Dann kann die Antwort von einem Back-End oder externen Dienst verarbeitet werden.

JavaScript-Beispielcode mit waitForComplete()

var headers = {'X-SOME-HEADER' : 'some value' };
var myRequest = new Request("http://www.example.com","GET",headers);
var exchange = httpClient.send(myRequest);
// Wait for the asynchronous GET request to finish
exchange.waitForComplete();

// Get and Process the response
if (exchange.isSuccess()) {
    var responseObj = exchange.getResponse().content.asJSON;
    return responseObj.access_token;
} else if (exchange.isError()) {
    throw new Error(exchange.getError());
}

Anti-Pattern

Die Verwendung von waitForComplete() nach dem Senden einer HTTP-Anfrage in JavaScript-Code wirkt sich auf die Leistung aus.

Betrachten Sie den folgenden JavaScript-Code, der waitForComplete() nach dem Senden einer HTTP-Anfrage aufruft.

Code für sample.js

// Send the HTTP request
var exchangeObj = httpClient.get("http://example.com");
// Wait until the request is completed
exchangeObj.waitForComplete();
// Check if the request was successful
if (exchangeObj.isSuccess())  {

    response = exchangeObj.getResponse();
    context.setVariable('example.status', response.status);
} else {
   error = exchangeObj.getError();
   context.setVariable('example.error', 'Woops: ' + error);
}

In diesem Beispiel:

  1. Der JavaScript-Code sendet eine HTTP-Anfrage an eine Back-End-API.
  2. Anschließend wird waitForComplete() aufgerufen, um die Ausführung anzuhalten, bis die Anfrage abgeschlossen ist.

    Die waitForComplete() API bewirkt, dass der Thread, in dem der JavaScript-Code ausgeführt wird, blockiert wird, bis das Back-End die Verarbeitung der Anfrage abgeschlossen hat und antwortet.

Es gibt eine Obergrenze für die Anzahl von Threads (30%), die gleichzeitig JavaScript-Code auf einem Message Processor ausführen können. Wenn dieses Limit erreicht ist, stehen keine Threads mehr zum Ausführen des JavaScript-Codes zur Verfügung. Wenn also zu viele gleichzeitige Anfragen die waitForComplete() API im JavaScript-Code ausführen, schlagen nachfolgende Anfragen mit der Fehlermeldung 500 Internal Server Error und Timed out fehl, bevor das Zeitlimit der JavaScript-Richtlinie überschritten wird.

Im Allgemeinen tritt dieses Szenario auf, wenn das Back-End für die Verarbeitung von Anfragen sehr lange benötigt oder hoher Traffic besteht.

Auswirkungen

  1. Die API-Anfragen schlagen mit 500 Internal Server Error und der Fehlermeldung Timed out fehl, wenn die Anzahl gleichzeitiger Anfragen, die waitForComplete() im JavaScript-Code ausführen, das vordefinierte Limit überschreitet.
  2. Das Diagnostizieren der Problemursache kann schwierig sein, da der JavaScript-Code mit dem Fehler Timed out fehlschlägt, obwohl das Zeitlimit für die jeweilige JavaScript-Richtlinie nicht verstrichen ist.

Best Practice

Verwenden Sie Callbacks im HTTP-Client, um den Callout-Code zu optimieren, die Leistung zu verbessern und die Verwendung von waitForComplete() im JavaScript-Code zu vermeiden. Diese Methode stellt sicher, dass die Ausführung von JavaScript durch den Thread erst blockiert wird, wenn die HTTP-Anfrage abgeschlossen ist.

Wenn ein Callback verwendet wird, sendet der Thread die HTTP-Anfragen im JavaScript-Code und kehrt zum Pool zurück. Da der Thread nicht mehr blockiert wird, kann er andere Anfragen verarbeiten. Sobald die HTTP-Anfrage abgeschlossen ist und der Callback ausgeführt werden kann, wird eine Aufgabe erstellt und der Aufgabenwarteschlange hinzugefügt. In einem der Threads aus dem Pool wird der Callback abhängig von der Priorität der Aufgabe ausgeführt.

JavaScript-Codebeispiel mit Callbacks in httpClient

function onComplete(response,error) {
 // Check if the HTTP request was successful
    if (response) {
      context.setVariable('example.status', response.status);
     } else {
      context.setVariable('example.error', 'Woops: ' + error);
     }
}
// Specify the callback Function as an argument
httpClient.get("http://example.com", onComplete);

Weitere Informationen