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

Estás consultando la documentación de Apigee Edge.
Consulta 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 de 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 eficaz 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 a servicios de backend o externos. El cliente HTTP es particularmente útil cuando se necesita realizar llamadas a varios servicios externos y mezclar 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 realizar una solicitud HTTP, es importante saber cuándo se completa, de modo 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 (correcto o con errores). 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

El uso de waitForComplete() después de enviar una solicitud HTTP en código JavaScript afectará el 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', 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.

Hay un límite superior para la cantidad de subprocesos (30%) que pueden ejecutar código JavaScript en un Message Processor en cualquier momento. Una vez que se alcance ese límite, no habrá subprocesos disponibles para ejecutar el código JavaScript. Por lo tanto, si hay demasiadas solicitudes simultáneas que ejecutan la API de waitForComplete() en el código JavaScript, las solicitudes posteriores fallarán y se mostrará el mensaje 500 Internal Server Error y el mensaje de error "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. El diagnóstico de la causa del problema puede ser complicado, ya que JavaScript falla con el error "Timed out" a pesar de que no ha transcurrido el límite de tiempo para la política específica de JavaScript.

Práctica recomendada

Utiliza devoluciones de llamada en el cliente HTTP para optimizar el código de texto destacado y mejorar el rendimiento. Además, evita el uso de 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 utiliza 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 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