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

Estás viendo la documentación de Apigee Edge.
Ve a la Documentación de Apigee X.
información

La política de JavaScript en Apigee Edge te permite agregar código personalizado que se ejecuta dentro del 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 HTTP. El cliente HTTP (o el objeto httpClient) se puede usar para realizar una o varias llamadas al backend o a los servicios externos. El cliente HTTP es particularmente útil cuando se necesita 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 completa la solicitud HTTP y se muestra una respuesta (correcta o con errores). Luego, se puede procesar la respuesta de un servicio externo o backend.

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.

Ten en cuenta 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', response1.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 se bloquee el subproceso que ejecuta el código JavaScript hasta que el backend termine de procesar la solicitud y responda.

Existe un límite superior para la cantidad de subprocesos (30%) que pueden ejecutar código JavaScript de forma simultánea en un Message Processor y en cualquier momento. Una vez 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 Error interno del servidor y "Se agotó el tiempo de espera" incluso antes de que se agote el tiempo de espera de la política de JavaScript.

En general, esta situación puede ocurrir si el backend tarda mucho tiempo en procesar solicitudes o si hay mucho tráfico.

Impacto

  1. Las solicitudes a la API fallarán con 500 Error interno del servidor y con el mensaje de error "Se agotó el tiempo de espera" cuando la cantidad de solicitudes simultáneas que ejecutan waitForComplete() en el código de JavaScript excede el predefinido límite.
  2. Diagnosticar la causa del problema puede ser complicado, ya que JavaScript falla y muestra el estado "Se agotó el tiempo de espera" a pesar de que 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. Después de que se complete la solicitud HTTP 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 con 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