Antipattern: use waitForComplete() no código JavaScript

Esta é a documentação do Apigee Edge.
Acesse Documentação da Apigee X.
informações

A política JavaScript no Apigee Edge 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 é útil principalmente quando é preciso fazer chamadas para vários serviços externos e combinar 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 solicitação HTTP real seja concluída.

As solicitações HTTP podem levar de alguns segundos a alguns minutos. Depois que uma solicitação HTTP for 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 será 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', response1.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 executar o código JavaScript. Portanto, se houver muitas solicitações simultâneas executando a API waitForComplete() no código JavaScript, as solicitações subsequentes apresentarão falha com uma mensagem de erro 500 Internal Server Error e uma mensagem de tempo limite atingido, mesmo antes 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 Errore 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 pré-definido.
  2. O diagnóstico da causa do problema pode ser complicado, porque o JavaScript falha com o erro "Tempo limite atingido", mesmo que o limite de tempo para a política específica do JavaScript não tenha sido atingido.

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 o thread em execução no JavaScript não seja bloqueado até que a solicitação HTTP seja concluída.

Quando um callback for usado, o thread 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. Um dos threads do pool executará o callback com base na prioridade da tarefa.

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