Antipatrón: usar waitForComplete() en código JavaScript

Estás consultando la documentación de Apigee y Apigee Hybrid.
Consulta la documentación de Apigee Edge.

La política de JavaScript te permite añadir código personalizado que se ejecuta en el contexto de un flujo de proxy de API. Por ejemplo, el código personalizado de la política de JavaScript se puede usar para lo siguiente:

  • Obtener y definir variables de flujo
  • Ejecutar lógica personalizada y gestionar errores
  • Extraer datos de solicitudes o respuestas
  • Editar dinámicamente la URL de destino backend
  • Añadir o quitar encabezados de forma dinámica de una solicitud o una respuesta
  • Analizar una respuesta JSON

Cliente HTTP

Una de las funciones más potentes de la política de JavaScript es el cliente HTTP. El cliente HTTP (u objeto httpClient) se puede usar para hacer una o varias llamadas a servicios backend o externos. El cliente HTTP es especialmente útil cuando es necesario hacer llamadas a varios servicios externos y combinar las respuestas en una sola API.

Código JavaScript de ejemplo que hace una llamada al backend con el objeto httpClient

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

El objeto httpClient expone dos métodos, get y send (send se usa en el código de ejemplo anterior), para enviar solicitudes HTTP. Ambos métodos son asíncronos y devuelven un objeto exchange antes de que se complete la solicitud HTTP.

Las solicitudes HTTP pueden tardar entre unos segundos y unos minutos. Después de enviar una solicitud HTTP, es importante saber cuándo se completa para poder procesar la respuesta. Una de las formas más habituales de determinar cuándo se completa la solicitud HTTP es invocar el método waitForComplete() del objeto exchange.

waitForComplete()

El método waitForComplete() pausa el hilo hasta que se completa la solicitud HTTP y se devuelve una respuesta (correcta o incorrecta). A continuación, se puede procesar la respuesta de un backend o un servicio externo.

Código JavaScript de ejemplo con 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());
}

Antipatrón

Usar waitForComplete() después de enviar una solicitud HTTP en código JavaScript tendrá consecuencias en el rendimiento.

Veamos el siguiente código JavaScript que llama a waitForComplete() después de enviar una solicitud HTTP.

Código de 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);
}

En este ejemplo:

  1. El código JavaScript envía una solicitud HTTP a una API de backend.
  2. A continuación, llama a waitForComplete() para pausar la ejecución hasta que se complete la solicitud.

    La API waitForComplete() hace que el subproceso que ejecuta el código JavaScript se bloquee hasta que el backend complete el procesamiento de la solicitud y responda.

Hay un límite máximo en el número de subprocesos (30%) que pueden ejecutar código JavaScript simultáneamente en un procesador de mensajes en cualquier momento. Una vez alcanzado ese límite, no habrá ningún hilo disponible para ejecutar el código JavaScript. Por lo tanto, si hay demasiadas solicitudes simultáneas que ejecutan la API waitForComplete() en el código JavaScript, las solicitudes posteriores fallarán con un mensaje de error 500 Internal Server Error y Timed out incluso antes de que se agote el tiempo de espera de la política de JavaScript.

Por lo general, este escenario puede producirse si el backend tarda mucho en procesar las solicitudes o si hay mucho tráfico.

Impacto

  1. Las solicitudes a la API fallarán con 500 Internal Server Error y con el mensaje de error Timed out cuando el número de solicitudes simultáneas que se ejecutan waitForComplete() en el código JavaScript supere el límite predefinido.
  2. Diagnosticar la causa del problema puede ser complicado, ya que el código JavaScript falla con el error Timed out aunque no haya transcurrido el tiempo límite de la política de JavaScript específica.

Práctica recomendada

Usa retrollamadas en el cliente HTTP para optimizar el código de llamada y mejorar el rendimiento, así como para evitar el uso de waitForComplete() en el código JavaScript. Este método asegura que el hilo que ejecuta JavaScript no se bloquee hasta que se complete la solicitud HTTP.

Cuando se usa una retrollamada, el hilo envía las solicitudes HTTP en el código JavaScript y vuelve al grupo. Como el hilo ya no está bloqueado, puede gestionar otras solicitudes. Una vez que se haya completado la solicitud HTTP y la retrollamada esté lista para ejecutarse, se creará una tarea y se añadirá a la cola de tareas. Uno de los subprocesos del grupo ejecutará la retrollamada en función de la prioridad de la tarea.

Código JavaScript de ejemplo que usa devoluciones de llamada en 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);

Más información