アンチパターン: JavaScript コードで waitForComplete() を使用する

Apigee Edge の JavaScript ポリシーを使用すると、API プロキシフローの処理中にカスタムコードを実行できます。たとえば、JavaScript ポリシーのカスタムコードは次の目的で使用できます。

  • フロー変数を取得して設定する
  • カスタム ロジックを実行し、障害処理を実施する
  • リクエストまたはレスポンスからデータを抽出する
  • バックエンドのターゲット URL を動的に編集する
  • リクエストまたはレスポンスに対して動的にヘッダーの追加または削除を行う
  • JSON レスポンスを解析する

HTTP クライアント

HTTP クライアントは、JavaScript ポリシーの高度な機能です。HTTP クライアント(httpClient オブジェクト)を使用すると、1 つまたは複数のバックエンド サービスまたは外部サービスを呼び出せます。HTTP クライアントが特に役立つのは、複数の外部サービスを呼び出して、レスポンスを単一の API でマッシュアップする必要がある場合です。

httpClient オブジェクトを使用してバックエンドを呼び出す JavaScript コードの例

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

httpClient オブジェクトは 2 つのメソッド getsend を公開し(send は上記のサンプルコードで使用)、HTTP リクエストを作成します。どちらのメソッドも非同期で、実際の HTTP リクエストが完了する前に exchange オブジェクトを返します。

HTTP リクエストは数秒から数分かかる場合があります。HTTP リクエストが行われた後、リクエストからのレスポンスを処理できるように、完了したタイミングを知ることが重要です。HTTP リクエストが完了したタイミングを判断する最も一般的な方法の 1 つは、exchange オブジェクトの waitForComplete() メソッドを呼び出すことです。

waitForComplete()

waitForComplete() メソッドは、HTTP リクエストが完了し、レスポンス(成功 / 失敗)が返されるまでスレッドを一時停止します。その後で、バックエンドまたは外部サービスからのレスポンスが処理できるようになります。

waitForComplete() を使用した JavaScript コードの例

    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());
    }
    

アンチパターン

JavaScript コードで HTTP リクエストを送信した後に waitForComplete() を使用すると、パフォーマンスに影響が出ます。

HTTP リクエストの送信後に waitForComplete() を呼び出す次の JavaScript コードを考えてみましょう。

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

この例では、次のような処理が行われます。

  1. JavaScript コードは HTTP リクエストをバックエンド API に送信します。
  2. 次に waitForComplete() を呼び出して、リクエストが完了するまで実行を一時停止します。

    waitForComplete() API を使用すると、バックエンドがリクエストの処理を完了して応答するまで、JavaScript コードを実行しているスレッドがブロックされます。

Message Processor で JavaScript コードを同時に実行できるスレッドの数には、常に上限があります(30%)。この上限に達すると、JavaScript コードを実行できるスレッドはなくなります。そのため、JavaScript コードで waitForComplete() API を実行する同時リクエストが多すぎる場合、JavaScript ポリシーがタイムアウトする前でも、後続のリクエストは、500 Internal Server Error で失敗し、「タイムアウト」エラー メッセージが表示されます。

一般に、このシナリオは、バックエンドがリクエストの処理に時間がかかる場合や、トラフィックが多い場合に発生する可能性があります。

影響

  1. JavaScript コードで waitForComplete() を実行する同時リクエストの数が事前定義された上限を超えると、API リクエストは 500 Internal Server Error で失敗し、エラー メッセージ「タイムアウト」が表示されます。
  2. 特定の JavaScript ポリシーの制限時間が経過していなくても JavaScript が「タイムアウト」エラーで失敗するため、問題の原因を診断するのは難しい場合があります。

ベスト プラクティス

HTTP クライアントで callback を使用して、コールアウト コードを合理化し、パフォーマンスを改善します。また JavaScript コードで waitForComplete() を使用しないようにします。このメソッドは、HTTP リクエストが完了するまで JavaScript を実行するスレッドがブロックされないようにします。

callback が使用されると、スレッドは HTTP コードを JavaScript コードで送信し、プールに戻ります。スレッドはブロックされなくなったため、他のリクエストを処理できます。HTTP リクエストが完了し、callback を実行する準備が整うと、タスクが作成され、タスクキューに追加されます。プールのスレッドの 1 つが、タスクの優先度に基づいて callback を実行します。

httpClient で callback を使用した JavaScript コードの例

    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);
    

関連情報