Antipattern: use waitForComplete() no código JavaScript

Esta é a documentação da Apigee e da Apigee híbrida.
Confira a documentação da Apigee Edge.

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

  • Receber e definir variáveis de fluxo
  • Executar lógica personalizada e executar o tratamento de falhas
  • Extrair dados de solicitações ou respostas
  • Editar dinamicamente o URL de destino do back-end
  • Adicionar ou remover dinamicamente cabeçalhos de uma solicitação ou resposta
  • Analisar uma resposta JSON

Cliente HTTP

Um recurso poderoso da política JavaScript é o cliente HTTP. O cliente HTTP (ou o objeto httpClient) pode ser usado para fazer uma ou várias chamadas para back-end ou serviços externos. O cliente HTTP é particularmente útil quando há a necessidade de fazer chamadas para vários serviços externos e misturar as respostas em uma única API.

Exemplo de código JavaScript que faz uma chamada para 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 amostra acima), para fazer solicitações HTTP. Ambos os métodos são assíncronos e retornam um objeto exchange antes que a própria solicitação HTTP seja concluída.

As solicitações HTTP podem levar de alguns segundos a alguns minutos. Depois que uma solicitação HTTP é feita, é importante saber quando ela será concluída, para que a resposta da solicitação possa ser processada. Uma das maneiras mais comuns de determinar quando a solicitação HTTP está concluída é invocando o método waitForComplete() do objeto exchange.

waitForComplete()

O método waitForComplete() pausa a linha de execução até que a solicitação HTTP seja concluída e uma resposta (sucesso/falha) seja retornada. Em seguida, a resposta de um back-end ou serviço externo 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());
}

Antipadrão

O uso de waitForComplete() após o envio de uma solicitação HTTP no código JavaScript terá implicações no desempenho.

Considere o seguinte código JavaScript que chama waitForComplete() depois de enviar uma solicitação 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 uma solicitação HTTP para uma API de back-end.
  2. Em seguida, ele chama waitForComplete() para pausar a execução até que a solicitação seja concluída.

    A API waitForComplete() faz com que a linha de execução que está executando o código JavaScript seja bloqueada até que o back-end conclua o processamento da solicitação e responda.

Há um limite máximo no número de linhas de execução (30%) que podem executar simultaneamente o código JavaScript em um processador de mensagens a qualquer momento. Depois que esse limite for atingido, não haverá nenhuma linha de execução disponível para executá-lo. Portanto, se houver muitas solicitações simultâneas executando a API waitForComplete() no código JavaScript, as solicitações subsequentes falharão com uma mensagem de erro 500 Internal Server Error e Timed out, antes mesmo da política JavaScript expirar.

Em geral, este cenário pode ocorrer se o back-end levar muito tempo para processar solicitações ou se houver muito tráfego.

Impacto

  1. As solicitações de API falharão com 500 Internal Server Error e com a mensagem de erro Timed out quando o número de solicitações simultâneas em execução no waitForComplete() no código JavaScript exceder o limite predefinido.
  2. Diagnosticar a causa do problema pode ser complicado, já que o JavaScript falha com o erro Timed out, mesmo que o limite de tempo para a política JavaScript específica não tenha terminado.

Prática recomendada

Use callbacks no cliente HTTP para simplificar o código de callout, melhorar o desempenho e evitar o uso de waitForComplete() no código JavaScript. Esse método garante que a linha de execução no JavaScript não seja bloqueada até que a solicitação HTTP seja concluída.

Quando um callback for usado, a linha de execução enviará as solicitações HTTP em código JavaScript e retornará ao pool. Como a linha de execução não está mais bloqueada, ela está disponível para processar outras solicitações. Depois que a solicitação HTTP for concluída e o callback estiver pronto para ser executado, uma tarefa será criada e adicionada à fila de tarefas. Uma das linhas de execução do pool executará o callback com base na prioridade da tarefa.

Exemplo de código JavaScript usando callbacks 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 adicional