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

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

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

  • Obtener y configurar variables de flujo
  • Ejecutar lógica personalizada y realizar un control de fallas
  • Extraer datos de solicitudes o respuestas
  • Editar de forma dinámica la URL de destino del backend
  • Agregar o quitar encabezados de una solicitud o respuesta de manera dinámica
  • Analizar una respuesta JSON

Cliente HTTP

Una función potente de la política de JavaScript es el cliente de HTTP. El cliente de HTTP (o el objeto httpClient) se puede usar para realizar una o varias llamadas a backend o servicios externos. El cliente de HTTP es particularmente útil cuando hay que realizar llamadas a múltiples servicios externos y combinar las respuestas en una sola API.

Ejemplo de código JavaScript que realiza 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 muestra anterior) para realizar solicitudes HTTP. Ambos métodos son asíncronos y muestran un objeto exchange antes de que se complete la solicitud HTTP real.

Las solicitudes HTTP pueden tardar unos segundos o unos minutos. Después de que se realiza una solicitud HTTP, es importante saber cuándo se completa para que se pueda procesar la respuesta de la solicitud. Una de las formas más comunes 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 subproceso hasta que se complete la solicitud HTTP y se muestre una respuesta (correcta o fallida). Luego, se puede procesar la respuesta de un backend o servicio externo.

Ejemplo de código JavaScript 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á implicancias de rendimiento.

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

Código para 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. Luego, llama a waitForComplete() para pausar la ejecución hasta que se complete la solicitud.

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

Existe un límite máximo en la cantidad de subprocesos (30%) que pueden ejecutar código JavaScript de forma simultánea en un Message Processor en cualquier momento. Después de que se alcance ese límite, no habrá ningún subproceso disponible para ejecutar el código JavaScript. Por lo tanto, si hay demasiadas solicitudes simultáneas ejecutando la API de 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.

En general, esto puede ocurrir si el backend tarda mucho tiempo en procesar las solicitudes o si el tráfico es alto.

Impacto

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

Práctica recomendada

Usa devoluciones de llamada en el cliente HTTP para optimizar el código de texto destacado y mejorar el rendimiento, y evita usar waitForComplete() en el código JavaScript. Este método garantiza que el subproceso que ejecuta JavaScript no se bloquee hasta que se complete la solicitud HTTP.

Cuando se usa una devolución de llamada, el subproceso envía las solicitudes HTTP en el código JavaScript y regresa al grupo. Debido a que el subproceso ya no está bloqueado, está disponible para manejar otras solicitudes. Una vez que la solicitud HTTP esté completa y la devolución de llamada esté lista para ejecutarse, se creará una tarea y se agregará a la lista de tareas en cola. Uno de los subprocesos del grupo ejecutará la devolución de llamada según la prioridad de la tarea.

Ejemplo de código JavaScript 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);

Lecturas adicionales