Antimodèle : Utiliser waitForComplete() dans le code JavaScript

Vous consultez la documentation d'Apigee et d'Apigee hybrid.
Consultez la documentation d'Apigee Edge.

La règle JavaScript vous permet d'ajouter du code personnalisé qui s'exécute dans le contexte d'un flux de proxy d'API. Par exemple, le code personnalisé de la règle JavaScript peut être utilisé pour :

  • Obtenir et définir les variables de flux
  • Exécuter une logique personnalisée et procéder à la gestion des erreurs
  • Extraire des données de requêtes ou de réponses
  • Modifier dynamiquement l'URL cible du backend
  • Ajouter ou supprimer de manière dynamique des en-têtes dans une requête ou une réponse
  • Analyser une réponse JSON

Client HTTP

Le client HTTP constitue une fonctionnalité puissante de la règle JavaScript. Le client HTTP (ou l'objet httpClient) peut être utilisé pour effectuer un ou plusieurs appels à des services de backend ou des services externes. Le client HTTP est particulièrement utile lorsqu'il doit effectuer des appels vers plusieurs services externes et générer les réponses dans une seule API.

Exemple de code JavaScript effectuant un appel vers le backend à l'aide d'un objet httpClient

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

L'objet httpClient expose deux méthodes get et send (send est utilisé dans l'exemple de code ci-dessus) pour effectuer des requêtes HTTP. Ces deux méthodes sont asynchrones et renvoient un objet exchange avant la fin de la requête HTTP.

Les requêtes HTTP peuvent prendre de quelques secondes à quelques minutes. Une fois la requête HTTP effectuée, il est important de savoir quand la requête est terminée, afin que la réponse de la requête puisse être traitée. L'une des méthodes les plus courantes pour déterminer le moment où la requête HTTP est terminée consiste à appeler la méthode waitForComplete() de l'objet exchange.

waitForComplete()

La méthode waitForComplete() met le thread en pause jusqu'à ce que la requête HTTP soit terminée et qu'une réponse (succès/échec) soit renvoyée. Ensuite, la réponse d'un backend ou d'un service externe peut être traitée.

Exemple de code JavaScript avec 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());
}

Antimodèle

L'utilisation de waitForComplete() après avoir envoyé une requête HTTP dans du code JavaScript aura des répercussions sur les performances.

Considérez le code JavaScript suivant qui appelle waitForComplete() après l'envoi d'une requête HTTP.

Code pour 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);
}

Dans cet exemple :

  1. Le code JavaScript envoie une requête HTTP à une API backend.
  2. Elle appelle ensuite waitForComplete() pour mettre en pause l'exécution jusqu'à la fin de la requête.

    L'API waitForComplete() entraîne le blocage du thread qui exécute le code JavaScript jusqu'à ce que le backend termine le traitement de la requête et y réponde.

Il existe une limite supérieure au nombre de threads (30 %) pouvant exécuter simultanément et à tout moment du code JavaScript sur un processeur de messages. Une fois cette limite atteinte, plus aucun thread n'est disponible pour exécuter le code JavaScript. Ainsi, si trop de requêtes simultanées exécutent l'API waitForComplete() dans le code JavaScript, les requêtes ultérieures échoueront avec un message d'erreur 500 Internal Server Error et Timed out avant même que la règle JavaScript n'expire.

En général, ce scénario peut se produire si le backend prend beaucoup de temps pour traiter les requêtes ou si le trafic est élevé.

Impact

  1. Les requêtes API échouent avec le message d'erreur 500 Internal Server Error et Timed out lorsque le nombre de requêtes simultanées exécutant waitForComplete() dans le code JavaScript dépasse la limite prédéfinie.
  2. Diagnostiquer la cause du problème n'est pas toujours évident, car le code JavaScript échoue avec une erreur Timed out même si le délai d'expiration de la règle JavaScript spécifique n'est pas écoulé.

Bonne pratique

Utilisez des rappels dans le client HTTP pour simplifier le code de l'appel et améliorer les performances, et éviter d'utiliser waitForComplete() dans le code JavaScript. Cette méthode permet de s'assurer que le thread qui exécute JavaScript n'est pas bloqué tant que la requête HTTP n'est pas terminée.

Lorsqu'un rappel est utilisé, le thread envoie les requêtes HTTP dans le code JavaScript et revient au pool. Étant donné que le thread n'est plus bloqué, il est disponible pour gérer d'autres requêtes. Une fois la requête HTTP terminée et le rappel prêt à être exécuté, une tâche est créée et ajoutée à la file d'attente de tâches. L'un des threads du pool exécutera le rappel en fonction de la priorité de la tâche.

Exemple de code JavaScript utilisant des rappels dans 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);

Documentation complémentaire