Antipattern: utilizzare waitForComplete() nel codice JavaScript

Stai visualizzando la documentazione di Apigee e Apigee hybrid.
Visualizza la documentazione di Apigee Edge.

Il criterio JavaScript consente di aggiungere codice personalizzato che viene eseguito nel contesto di un flusso del proxy API. Ad esempio: il codice personalizzato nel criterio JavaScript può essere usato per:

  • Ottieni e imposta variabili di flusso
  • Esegui logica personalizzata e gestione degli errori
  • Estrarre i dati da richieste o risposte
  • Modificare dinamicamente l'URL target di backend
  • Aggiungere o rimuovere dinamicamente le intestazioni da una richiesta o una risposta
  • Analizza una risposta JSON

Client HTTP

Una funzionalità potente del criterio JavaScript è il client HTTP. È possibile utilizzare il client HTTP (o l'oggetto httpClient) per effettuare una o più chiamate a servizi di backend o esterni. Il client HTTP è particolarmente utile quando è necessario effettuare chiamate a più servizi esterni e combinare le risposte in un'unica API.

Esempio di codice JavaScript 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 viene utilizzato nel codice di esempio riportato sopra) per effettuare richieste HTTP. Entrambi i metodi sono asincroni e restituiscono un oggetto exchange prima del completamento della richiesta HTTP effettiva.

Le richieste HTTP potrebbero richiedere da alcuni secondi ad alcuni minuti. Dopo aver inviato una richiesta HTTP, è importante sapere quando è stata completata in modo da poter elaborare la risposta. Uno dei modi più comuni per determinare quando la richiesta HTTP è completa è richiamare il metodo waitForComplete() dell'oggetto exchange.

waitForComplete()

Il metodo waitForComplete() mette in pausa il thread finché la richiesta HTTP non viene completata e viene restituita una risposta (esito positivo/non riuscito). La risposta di un servizio di backend o esterno può quindi essere elaborata.

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 sul rendimento.

Considera il seguente codice JavaScript che chiama waitForComplete() dopo l'invio 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', response.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 backend.
  2. Quindi chiama waitForComplete() per mettere in pausa l'esecuzione fino al completamento della richiesta.

    L'API waitForComplete() causa il thread che esegue il codice JavaScript deve essere bloccato finché il backend non completa l'elaborazione della richiesta e risponde.

Esiste un limite massimo per il numero di thread (30%) che possono eseguire contemporaneamente codice JavaScript su un elaboratore di messaggi in qualsiasi momento. Una volta raggiunto questo limite, non saranno disponibili thread per eseguire il codice JavaScript. Quindi, se ci sono troppe richieste simultanee eseguendo l'API waitForComplete() nel codice JavaScript, poi richiede avrà esito negativo con un messaggio di errore 500 Internal Server Error e Timed out anche prima Timeout del criterio JavaScript.

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

Impatto

  1. Le richieste API non andranno a buon fine con 500 Internal Server Error e con il messaggio di errore Timed out quando il numero di richieste simultanee che eseguono waitForComplete() nel codice JavaScript supera il limite predefinito.
  2. La diagnosi della causa del problema può essere complicata perché JavaScript non funziona con l'errore Timed out anche se il limite di tempo per il criterio JavaScript specifico non è scaduto.

Best practice

Utilizza i callback nel client HTTP per semplificare il codice callout e migliorare il rendimento e evita di utilizzare waitForComplete() nel codice JavaScript. Questo metodo garantisce che il thread che esegue JavaScript non venga bloccato fino al completamento della richiesta HTTP.

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

Esempio di codice JavaScript con 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