Antipattern: use waitForComplete() no código JavaScript

Está a ver a documentação do Apigee e do Apigee Hybrid.
Veja a documentação do Apigee Edge.

A política de JavaScript permite-lhe adicionar código personalizado que é executado no contexto de um fluxo de proxy de API. Por exemplo, o código personalizado na política de JavaScript pode ser usado para:

  • Obtenha e defina variáveis de fluxo
  • Execute lógica personalizada e realize o processamento de falhas
  • Extraia dados de pedidos ou respostas
  • Edite dinamicamente o URL de destino de back-end
  • Adicione ou remova dinamicamente cabeçalhos de um pedido ou de uma resposta
  • Analise uma resposta JSON

Cliente HTTP

Uma funcionalidade poderosa da política de JavaScript é o cliente HTTP. O cliente HTTP (ou o objeto httpClient) pode ser usado para fazer uma ou várias chamadas para serviços externos ou de back-end. O cliente HTTP é particularmente útil quando é necessário fazer chamadas para vários serviços externos e combinar as respostas numa única API.

Exemplo de código JavaScript que faz uma chamada ao back-end com o objeto httpClient

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

O objeto httpClient expõe dois métodos get e send (send é usado no código de exemplo acima) para fazer pedidos HTTP. Ambos os métodos são assíncronos e devolvem um objeto exchange antes de o pedido HTTP real ser concluído.

Os pedidos HTTP podem demorar alguns segundos a alguns minutos. Depois de fazer um pedido HTTP, é importante saber quando é concluído para que a resposta do pedido possa ser processada. Uma das formas mais comuns de determinar quando o pedido HTTP está concluído é invocar o método waitForComplete() do objeto exchange.

waitForComplete()

O método waitForComplete() pausa a discussão até que o pedido HTTP seja concluído e seja devolvida uma resposta (êxito/falha). Em seguida, a resposta de um serviço externo ou de back-end pode ser processada.

Exemplo de código JavaScript com 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());
}

Antipattern

A utilização de waitForComplete() após o envio de um pedido HTTP no código JavaScript tem implicações no desempenho.

Considere o seguinte código JavaScript que chama waitForComplete() após o envio de um pedido 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);
}

Neste exemplo:

  1. O código JavaScript envia um pedido HTTP a uma API de back-end.
  2. Em seguida, chama waitForComplete() para pausar a execução até que o pedido seja concluído.

    A waitForComplete() API faz com que a thread que está a executar o código JavaScript seja bloqueada até que o back-end conclua o processamento do pedido e responda.

Existe um limite superior para o número de threads (30%) que podem executar código JavaScript em simultâneo num processador de mensagens em qualquer altura. Depois de atingir esse limite, não existem mais threads disponíveis para executar o código JavaScript. Assim, se existirem demasiados pedidos simultâneos a executar a API waitForComplete() no código JavaScript, os pedidos subsequentes falham com uma mensagem de erro 500 Internal Server Error e Timed out, mesmo antes de o tempo limite da política de JavaScript expirar.

Em geral, este cenário pode ocorrer se o back-end demorar muito tempo a processar pedidos ou se houver um volume elevado de tráfego.

Impacto

  1. Os pedidos da API falham com 500 Internal Server Error e com a mensagem de erro Timed out quando o número de pedidos simultâneos que executam waitForComplete() no código JavaScript excede o limite predefinido.
  2. O diagnóstico da causa do problema pode ser complicado, uma vez que o JavaScript falha com o erro Timed out , mesmo que o limite de tempo para a política de JavaScript específica não tenha decorrido.

Prática recomendada

Use callbacks no cliente HTTP para simplificar o código de chamada e melhorar o desempenho, e evite usar waitForComplete() no código JavaScript. Este método garante que a thread que executa JavaScript não é bloqueada até que o pedido HTTP seja concluído.

Quando é usado um retorno de chamada, a thread envia os pedidos HTTP no código JavaScript e regressa ao conjunto. Uma vez que a thread já não está bloqueada, está disponível para processar outros pedidos. Depois de o pedido HTTP estar concluído e o callback estar pronto para ser executado, é criada uma tarefa e adicionada à fila de tarefas. Uma das discussões do conjunto executa o callback com base na prioridade da tarefa.

Exemplo de código JavaScript que usa chamadas de retorno em 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);

Leitura complementar