Anti-pattern: utilizza WaitForComplete() nel codice JavaScript

Stai visualizzando la documentazione di Apigee Edge.
Vai alla documentazione di Apigee X.
informazioni

Il criterio JavaScript in Apigee Edge consente di aggiungere codice personalizzato che viene eseguito nel contesto di un flusso proxy API. Ad esempio, il codice personalizzato nel criterio JavaScript può essere utilizzato per:

  • Recupero e impostazione delle variabili di flusso
  • Esegui logica personalizzata ed esegui la gestione degli errori
  • Estrae dati da richieste o risposte
  • Modificare dinamicamente l'URL di destinazione del backend
  • Aggiungere o rimuovere in modo dinamico le intestazioni da una richiesta o una risposta
  • Analizza una risposta JSON

Client HTTP

Una funzionalità efficace del criterio JavaScript è il client HTTP. Il client HTTP (o l'oggetto httpClient) può essere utilizzato per effettuare una o più chiamate al backend o ai servizi esterni. Il client HTTP è particolarmente utile quando è necessario effettuare chiamate a più servizi esterni e combinare le risposte in una singola API.

Codice JavaScript di esempio che effettua una chiamata al backend con l'oggetto httpClient

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

L'oggetto httpClient espone due metodi get e send (send è utilizzato nel codice campione precedente) per effettuare richieste HTTP. Entrambi i metodi sono asincroni e restituiscono un oggetto exchange prima che l'effettiva richiesta HTTP venga completata.

Le richieste HTTP potrebbero richiedere da pochi secondi a qualche minuto. Dopo aver effettuato una richiesta HTTP, è importante sapere quando viene completata, in modo che la risposta della richiesta possa essere elaborata. Uno dei modi più comuni per determinare quando la richiesta HTTP è completa consiste nel richiamare il metodo waitForComplete() dell'oggetto exchange.

waitForComplete()

Il metodo waitForComplete() mette in pausa il thread finché la richiesta HTTP non viene completata e non viene restituita una risposta (operazione riuscita/non riuscita). Quindi, può essere elaborata la risposta da un backend o da un servizio esterno.

Codice JavaScript di esempio 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());
}

Antipattern

L'utilizzo di waitForComplete() dopo l'invio di una richiesta HTTP nel codice JavaScript avrà implicazioni sulle prestazioni.

Considera il seguente codice JavaScript che chiama waitForComplete() dopo aver inviato una richiesta HTTP.

Codice per 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);
}

In questo esempio:

  1. Il codice JavaScript invia una richiesta HTTP a un'API di backend.
  2. Quindi chiama waitForComplete() per mettere in pausa l'esecuzione fino al completamento della richiesta.

    L'API waitForComplete() fa sì che il thread che esegue il codice JavaScript venga bloccato finché il backend non completa l'elaborazione della richiesta e risponde.

Esiste un limite superiore al numero di thread (30%) che possono eseguire contemporaneamente il codice JavaScript su un processore di messaggi in qualsiasi momento. Una volta raggiunto questo limite, non ci saranno thread disponibili per l'esecuzione del codice JavaScript. Quindi, se sono presenti troppe richieste in parallelo che eseguono l'API waitForComplete() nel codice JavaScript, le richieste successive non andranno a buon fine e verranno visualizzati un errore interno 500 del server e un messaggio di errore "Timeout" anche prima del timeout del criterio JavaScript.

In generale, questo scenario può verificarsi se il backend impiega molto tempo per elaborare le richieste o se c'è un traffico elevato.

Impatto

  1. Le richieste API avranno esito negativo con 500 errori interni del server e il messaggio di errore "Timeout" quando il numero di richieste in esecuzione waitForComplete() in parallelo nel codice JavaScript supera il limite predefinito.
  2. La diagnosi della causa del problema può essere difficoltosa poiché JavaScript non funziona e viene visualizzato l'errore "Timeout", anche se non è ancora trascorso il limite di tempo del criterio JavaScript specifico.

Best practice

Utilizza i callback nel client HTTP per semplificare il codice callout, migliorare le prestazioni ed evitare di utilizzare waitForComplete() nel codice JavaScript. Questo metodo garantisce che il thread che esegue JavaScript non sia bloccato fino al completamento della richiesta HTTP.

Quando viene utilizzato un callback, il thread invia le richieste HTTP nel codice JavaScript e torna al pool. Poiché il thread non è più bloccato, è disponibile per gestire altre richieste. Dopo che la richiesta HTTP è stata completata e il callback è pronto per essere eseguito, viene creata un'attività che viene aggiunta alla coda di attività. Uno dei thread del pool eseguirà il callback in base alla priorità dell'attività.

Codice JavaScript di esempio utilizzando i callback in 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);

Per approfondire